जावा 8 स्ट्रीम फ्लैटपाइप विधि उदाहरण


85

मैं आगामी जाँच कर रहा हूँ Java update, अर्थात् Java 8 or JDK 8:। हां, मैं अधीर हूं, बहुत कुछ नया है, लेकिन, कुछ ऐसा है जो मुझे समझ नहीं आ रहा है, कुछ सरल कोड:

final Stream<Integer>stream = Stream.of(1,2,3,4,5,6,7,8,9,10);
stream.flatMap();

javadocs हैं

public <R> Stream<R> flatMap(Function<? super T,? extends Stream<? extends R>> mapper)

इस स्ट्रीम के प्रत्येक तत्व को बदलने के परिणामों से युक्त एक धारा देता है जिसमें प्रत्येक तत्व को प्रदान की गई मैपिंग फ़ंक्शन को लागू करके उत्पादित मैप्ड स्ट्रीम की सामग्री होती है। प्रत्येक मैप्ड स्ट्रीम को इस स्ट्रीम में रखे जाने के बाद बंद कर दिया गया है। (यदि एक मैप्ड स्ट्रीम शून्य है, तो इसके बजाय एक खाली स्ट्रीम का उपयोग किया जाता है।) यह एक मध्यवर्ती ऑपरेशन है।

अगर कोई किसी के बारे में कुछ सरल वास्तविक जीवन उदाहरण बनाता है flatMap, तो आप इसकी सराहना करेंगे कि आप इसे पिछले जावा संस्करणों में Java[6,7]कैसे कोडित कर सकते हैं और कैसे आप उसी रूटीन का उपयोग करके कोड बना सकते हैं Java 8


2
इंटरनेट पर फ्लैटप्ला (कम से कम के लिए, और वे मूल रूप से एक ही हैं :)) का उपयोग करने के लगभग एक लाख उदाहरण हैं, क्या उन्होंने खोज करने की कोशिश की है? इसके साथ शुरू करने के लिए एक: brunton-spall.co.uk/post/2011/12/02/…
पीटर स्वेन्सन

3
मुझे समझ नहीं आ रहा है कि स्काला मैंने कभी स्कैला के साथ काम नहीं किया है
चिपेरॉर्टिज़

मेरा मतलब है कि फ्लैटपाइप एक सामान्य अवधारणा है जो अब जावा के साथ-साथ स्काला में भी मौजूद है।
पीटर स्वेन्सन

ठीक है मैं इसके बारे में और अधिक पढ़ूंगा धन्यवाद आदमी।
चिपरोर्टिज़

10
जावा में फ्लैटपाइप एक ही विचार है, लेकिन धाराओं के साथ काफी अलग दिखता है। Scala के लिए लोगों को इंगित न करें!
कक्षीय जूल

जवाबों:


158

यह flatMapएक स्ट्रीम के लिए कोई मतलब नहीं है जो पहले से ही सपाट है, जैसे Stream<Integer>आपने अपने प्रश्न में दिखाया है।

हालांकि, अगर आपके पास एक Stream<List<Integer>>समय था तो यह समझ में आता है और आप ऐसा कर सकते हैं:

Stream<List<Integer>> integerListStream = Stream.of(
    Arrays.asList(1, 2), 
    Arrays.asList(3, 4), 
    Arrays.asList(5)
);

Stream<Integer> integerStream = integerListStream .flatMap(Collection::stream);
integerStream.forEach(System.out::println);

जो प्रिंट करेगा:

1
2
3
4
5

इस प्री-जावा 8 को करने के लिए आपको बस एक लूप की आवश्यकता है:

List<List<Integer>> integerLists = Arrays.asList(
    Arrays.asList(1, 2), 
    Arrays.asList(3, 4), 
    Arrays.asList(5)
)

List<Integer> flattened = new ArrayList<>();

for (List<Integer> integerList : integerLists) {
    flattened.addAll(integerList);
}

for (Integer i : flattened) {
    System.out.println(i);
}

113

उदाहरण दिया

कल्पना करें कि आप निम्नलिखित अनुक्रम बनाना चाहते हैं: 1, 2, 2, 3, 3, 3, 4, 4, 4, 4 आदि (दूसरे शब्दों में: 1x1, 2x2, 3x3 आदि)।

इसके साथ flatMapऐसा लग सकता है:

IntStream sequence = IntStream.rangeClosed(1, 4)
                          .flatMap(i -> IntStream.iterate(i, identity()).limit(i));
sequence.forEach(System.out::println);

कहाँ पे:

  • IntStream.rangeClosed(1, 4)int1 से 4 तक की एक धारा बनाता है , समावेशी
  • IntStream.iterate(i, identity()).limit(i)i की लंबाई की एक धारा बनाता है int- तो इस पर लागू i = 4एक धारा बनाता है:4, 4, 4, 4
  • flatMap धारा को "समतल" करता है और मूल धारा में "समेटता है"

जावा <8 के साथ आपको दो नेस्टेड छोरों की आवश्यकता होगी:

List<Integer> list = new ArrayList<>();
for (int i = 1; i <= 4; i++) {
    for (int j = 0; j < i; j++) {
        list.add(i);
    }
}

वास्तविक विश्व उदाहरण

मान लीजिए कि मेरे पास एक है List<TimeSeries>जहां प्रत्येक TimeSeriesअनिवार्य रूप से एक है Map<LocalDate, Double>। मैं उन सभी तारीखों की सूची प्राप्त करना चाहता हूं जिनके लिए कम से कम एक समय श्रृंखला का एक मूल्य है। flatMapबचाव के लिए:

list.stream().parallel()
    .flatMap(ts -> ts.dates().stream()) // for each TS, stream dates and flatmap
    .distinct()                         // remove duplicates
    .sorted()                           // sort ascending
    .collect(toList());

न केवल यह पठनीय है, लेकिन अगर आपको अचानक 100k तत्वों को संसाधित करने की आवश्यकता है, तो बस जोड़ने parallel()से आप किसी भी समवर्ती कोड लिखने के बिना प्रदर्शन में सुधार करेंगे।


14
स्वीकृत उत्तर की तुलना में दोनों उदाहरण बहुत बेहतर हैं।
सेबस्टियन ग्राफ

संकलक पहचान के बारे में शिकायत करता है () अपरिभाषित के
निर्मल

2
@ user3320018 आपको स्थैतिक आयात करने की आवश्यकता है Function.identity
assylias

@assylias मैंने java.util.function आयात करने की कोशिश की। लेकिन काम नहीं किया, मैं java 8 के लिए नया हूं और यह java 8 विशिष्ट नहीं हो सकता है या नहीं, लेकिन क्या आप कृपया मुझे बता सकते हैं कि उस त्रुटि को कैसे हटाया जाए।
निर्मल

4
import static java.util.function.Function.identity;
अस्वच्छता

18

वाक्यांशों की सूची से ASC द्वारा छांटे गए अद्वितीय शब्दों को निकालें:

List<String> phrases = Arrays.asList(
        "sporadic perjury",
        "confounded skimming",
        "incumbent jailer",
        "confounded jailer");

List<String> uniqueWords = phrases
        .stream()
        .flatMap(phrase -> Stream.of(phrase.split("\\s+")))
        .distinct()
        .sorted()
        .collect(Collectors.toList());
System.out.println("Unique words: " + uniqueWords);

... और आउटपुट:

Unique words: [confounded, incumbent, jailer, perjury, skimming, sporadic]

11

क्या मैं अकेला हूँ जो उबाऊ सूचियों को उबाऊ पाता है? ;-)

वस्तुओं के साथ प्रयास करते हैं। वैसे वास्तविक दुनिया उदाहरण है।

दिया गया: दोहराव कार्य का प्रतिनिधित्व करने वाली वस्तु। महत्वपूर्ण कार्य क्षेत्रों के बारे में: रिमाइंडर बजना शुरू हो रहे हैं startऔर प्रत्येक repeatPeriod repeatUnit(जैसे 5 घंटे) को दोहराते हैं और repeatCountकुल में रिमाइंडर होंगे (जिसमें एक को शुरू करना भी शामिल है)।

लक्ष्य: कार्य प्रतियों की एक सूची प्राप्त करें, प्रत्येक कार्य अनुस्मारक आमंत्रण के लिए एक।

List<Task> tasks =
            Arrays.asList(
                    new Task(
                            false,//completed sign
                            "My important task",//task name (text)
                            LocalDateTime.now().plus(2, ChronoUnit.DAYS),//first reminder(start)
                            true,//is task repetitive?
                            1,//reminder interval
                            ChronoUnit.DAYS,//interval unit
                            5//total number of reminders
                    )
            );

tasks.stream().flatMap(
        x -> LongStream.iterate(
                x.getStart().toEpochSecond(ZoneOffset.UTC),
                p -> (p + x.getRepeatPeriod()*x.getRepeatUnit().getDuration().getSeconds())
        ).limit(x.getRepeatCount()).boxed()
        .map( y -> new Task(x,LocalDateTime.ofEpochSecond(y,0,ZoneOffset.UTC)))
).forEach(System.out::println);

आउटपुट:

Task{completed=false, text='My important task', start=2014-10-01T21:35:24, repeat=false, repeatCount=0, repeatPeriod=0, repeatUnit=null}
Task{completed=false, text='My important task', start=2014-10-02T21:35:24, repeat=false, repeatCount=0, repeatPeriod=0, repeatUnit=null}
Task{completed=false, text='My important task', start=2014-10-03T21:35:24, repeat=false, repeatCount=0, repeatPeriod=0, repeatUnit=null}
Task{completed=false, text='My important task', start=2014-10-04T21:35:24, repeat=false, repeatCount=0, repeatPeriod=0, repeatUnit=null}
Task{completed=false, text='My important task', start=2014-10-05T21:35:24, repeat=false, repeatCount=0, repeatPeriod=0, repeatUnit=null}

पुनश्च: अगर किसी ने एक सरल समाधान सुझाया है, तो मैं सराहना करूंगा, मैं एक समर्थक नहीं हूं।

अद्यतन: @RBz ने विस्तृत विवरण के लिए कहा, तो यह यहाँ है। मूल रूप से फ्लैटपाइप सभी तत्वों को आउटपुट स्ट्रीम में किसी अन्य स्ट्रीम के अंदर स्ट्रीम से डालता है। बहुत सारी धाराएँ यहाँ :)। इसलिए, प्रारंभिक कार्य में प्रत्येक कार्य के लिए लंबोदर अभिव्यक्ति x -> LongStream.iterate...लंबे मानों की एक धारा बनाती है जो कार्य प्रारंभ क्षणों का प्रतिनिधित्व करती है। यह धारा x.getRepeatCount()उदाहरणों तक सीमित है । यह मूल्यों से शुरू होता है x.getStart().toEpochSecond(ZoneOffset.UTC)और प्रत्येक अगले मूल्य को लैम्ब्डा का उपयोग करके गणना की जाती है p -> (p + x.getRepeatPeriod()*x.getRepeatUnit().getDuration().getSeconds()boxed()एक लंबी आवरण उदाहरण के रूप में प्रत्येक लंबे मूल्य के साथ धारा लौटाता है। फिर उस धारा में प्रत्येक लॉन्ग को नए टास्क उदाहरणों में मैप किया जाता है जो अब दोहराए नहीं जाते हैं और सटीक निष्पादन समय होते हैं। इस नमूने में इनपुट सूची में केवल एक टास्क है। लेकिन कल्पना कीजिए कि आपके पास एक हजार है। तब आपके पास टास्क ऑब्जेक्ट्स की 1000 धाराओं की एक धारा होगी। और क्याflatMapयहाँ सभी स्ट्रीम से सभी कार्य एक ही आउटपुट स्ट्रीम पर डाल रहा है। यह सब मुझे समझ में आ रहा है। आपके सवाल के लिए धन्यवाद!


8
Am I the only one who finds unwinding lists boring?+1
व्हाइटफिन

3
मुझे इस उदाहरण को समझना बहुत कठिन है। :(
RBz

@RBz स्ट्रीम ऑपरेशन को कभी-कभी समझना आसान नहीं होता है, खासकर अगर इसमें एक से अधिक ऑपरेशन शामिल हों। हालांकि यह अभ्यास की बात है। सबसे अच्छा आप यह कर सकते हैं कि नमूने से हर अस्पष्ट शब्द को गूगल करें और इसे स्वयं उपयोग करने का प्रयास करें। वास्तव में सामान्य अनिवार्य शैली का नमूना (और कभी-कभी तेज) समझने में बहुत आसान होता। तो बस सोचें कि क्या आपको वास्तव में धाराओं का उपयोग करने की आवश्यकता है।
Aleksandr Kravets

उत्तर के लिए धन्यवाद आदमी। हालाँकि मैं स्ट्रीम अवधारणाओं के साथ काफी ठीक हूँ। यहां मुझे जो परेशानी हो रही है, वह विशिष्ट है। मैं टाइम आपी के साथ इतना अच्छा नहीं था, लेकिन यहां तक ​​कि इसके माध्यम से पढ़ा भी मुझे समझने में मदद नहीं कर रहा है कि यहां क्या हो रहा है। हो सकता है मैं भोला हूँ, लेकिन आपके उत्तर के लिए थोड़ा और स्पष्टीकरण देना बहुत अच्छा होगा। यह वास्तव में मुझे आपके उदाहरण को समझने में मदद करेगा। मुझे पता है, मैं सिर्फ जिज्ञासा में बंद हूँ! :)
RBz

अद्भुत उदाहरण ... शुरुआत में समझने के लिए थोड़ा कठिन है, लेकिन एक बार जब मैं इसे अपनी आईडीई में चलाता हूं ... तो शक्तिशाली विकल्प !! आपका बहुत बहुत धन्यवाद !
क्रिस्टियानो

2

यह विधि एक फ़ंक्शन को एक तर्क के रूप में लेती है, यह फ़ंक्शन एक पैरामीटर टी को इनपुट तर्क के रूप में स्वीकार करता है और पैरामीटर आर की एक धारा को रिटर्न मान के रूप में वापस करता है। जब यह फ़ंक्शन इस स्ट्रीम के प्रत्येक तत्व पर लागू होता है, तो यह नए मानों की एक स्ट्रीम तैयार करता है। प्रत्येक तत्व द्वारा उत्पन्न इन नई धाराओं के सभी तत्वों को फिर एक नई धारा में कॉपी किया जाता है, जो इस पद्धति का एक वापसी मूल्य होगा।

http://codedestine.com/java-8-stream-flatmap-method/


2

एक बहुत ही सरल उदाहरण: नामों की एक सूची प्राप्त करने के लिए पूर्ण नामों की एक सूची को विभाजित करें, चाहे पहले या आखिरी की

 List<String> fullNames = Arrays.asList("Barry Allen", "Bruce Wayne", "Clark Kent");

 fullNames.stream()
            .flatMap(fullName -> Pattern.compile(" ").splitAsStream(fullName))
            .forEach(System.out::println);

यह प्रिंट करता है:

Barry
Allen
Bruce
Wayne
Clark
Kent

1

अगर यह दिया रहे:

  public class SalesTerritory
    {
        private String territoryName;
        private Set<String> geographicExtents;

        public SalesTerritory( String territoryName, Set<String> zipCodes )
        {
            this.territoryName = territoryName;
            this.geographicExtents = zipCodes;
        }

        public String getTerritoryName()
        {
            return territoryName;
        }

        public void setTerritoryName( String territoryName )
        {
            this.territoryName = territoryName;
        }

        public Set<String> getGeographicExtents()
        {
            return geographicExtents != null ? Collections.unmodifiableSet( geographicExtents ) : Collections.emptySet();
        }

        public void setGeographicExtents( Set<String> geographicExtents )
        {
            this.geographicExtents = new HashSet<>( geographicExtents );
        }

        @Override
        public int hashCode()
        {
            int hash = 7;
            hash = 53 * hash + Objects.hashCode( this.territoryName );
            return hash;
        }

        @Override
        public boolean equals( Object obj )
        {
            if ( this == obj ) {
                return true;
            }
            if ( obj == null ) {
                return false;
            }
            if ( getClass() != obj.getClass() ) {
                return false;
            }
            final SalesTerritory other = (SalesTerritory) obj;
            if ( !Objects.equals( this.territoryName, other.territoryName ) ) {
                return false;
            }
            return true;
        }

        @Override
        public String toString()
        {
            return "SalesTerritory{" + "territoryName=" + territoryName + ", geographicExtents=" + geographicExtents + '}';
        }

    }

और इस:

public class SalesTerritories
{
    private static final Set<SalesTerritory> territories
        = new HashSet<>(
            Arrays.asList(
                new SalesTerritory[]{
                    new SalesTerritory( "North-East, USA",
                                        new HashSet<>( Arrays.asList( new String[]{ "Maine", "New Hampshire", "Vermont",
                                                                                    "Rhode Island", "Massachusetts", "Connecticut",
                                                                                    "New York", "New Jersey", "Delaware", "Maryland",
                                                                                    "Eastern Pennsylvania", "District of Columbia" } ) ) ),
                    new SalesTerritory( "Appalachia, USA",
                                        new HashSet<>( Arrays.asList( new String[]{ "West-Virgina", "Kentucky",
                                                                                    "Western Pennsylvania" } ) ) ),
                    new SalesTerritory( "South-East, USA",
                                        new HashSet<>( Arrays.asList( new String[]{ "Virginia", "North Carolina", "South Carolina",
                                                                                    "Georgia", "Florida", "Alabama", "Tennessee",
                                                                                    "Mississippi", "Arkansas", "Louisiana" } ) ) ),
                    new SalesTerritory( "Mid-West, USA",
                                        new HashSet<>( Arrays.asList( new String[]{ "Ohio", "Michigan", "Wisconsin", "Minnesota",
                                                                                    "Iowa", "Missouri", "Illinois", "Indiana" } ) ) ),
                    new SalesTerritory( "Great Plains, USA",
                                        new HashSet<>( Arrays.asList( new String[]{ "Oklahoma", "Kansas", "Nebraska",
                                                                                    "South Dakota", "North Dakota",
                                                                                    "Eastern Montana",
                                                                                    "Wyoming", "Colorada" } ) ) ),
                    new SalesTerritory( "Rocky Mountain, USA",
                                        new HashSet<>( Arrays.asList( new String[]{ "Western Montana", "Idaho", "Utah", "Nevada" } ) ) ),
                    new SalesTerritory( "South-West, USA",
                                        new HashSet<>( Arrays.asList( new String[]{ "Arizona", "New Mexico", "Texas" } ) ) ),
                    new SalesTerritory( "Pacific North-West, USA",
                                        new HashSet<>( Arrays.asList( new String[]{ "Washington", "Oregon", "Alaska" } ) ) ),
                    new SalesTerritory( "Pacific South-West, USA",
                                        new HashSet<>( Arrays.asList( new String[]{ "California", "Hawaii" } ) ) )
                }
            )
        );

    public static Set<SalesTerritory> getAllTerritories()
    {
        return Collections.unmodifiableSet( territories );
    }

    private SalesTerritories()
    {
    }

}

हम फिर ऐसा कर सकते हैं:

System.out.println();
System.out
    .println( "We can use 'flatMap' in combination with the 'AbstractMap.SimpleEntry' class to flatten a hierarchical data-structure to a set of Key/Value pairs..." );
SalesTerritories.getAllTerritories()
    .stream()
    .flatMap( t -> t.getGeographicExtents()
        .stream()
        .map( ge -> new SimpleEntry<>( t.getTerritoryName(), ge ) )
    )
    .map( e -> String.format( "%-30s : %s",
                              e.getKey(),
                              e.getValue() ) )
    .forEach( System.out::println );
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.