मैं जावा 8 में एक सूची में सूचियों की सूची कैसे बदल सकता हूं?


532

यदि मेरे पास एक है List<List<Object>>, तो मैं List<Object>जावा 8 की सुविधाओं का उपयोग करके इसे एक ही पुनरावृत्ति क्रम में सभी वस्तुओं में कैसे बदल सकता हूं ?

जवाबों:


950

आप flatMapएक ही स्ट्रीम में आंतरिक सूचियों (स्ट्रीम में बदलने के बाद) को समतल करने के लिए उपयोग कर सकते हैं , और फिर एक सूची के परिणाम को इकट्ठा कर सकते हैं:

List<List<Object>> list = ...
List<Object> flat = 
    list.stream()
        .flatMap(List::stream)
        .collect(Collectors.toList());

11
@ वर्षाजी सच है, लेकिन किसी कारण से मैं लंबोदर अभिव्यक्ति पसंद करता हूं। शायद मुझे :::)
एरण

25
Class::methodपहली बार में थोड़ा अजीब लगता है, लेकिन इसका यह लाभ है कि यह घोषित करता है कि आप किस प्रकार की वस्तु से मैप कर रहे हैं। यह एक ऐसी चीज है जिसे आप अन्यथा धाराओं में खो देते हैं।
ArneHugo

2
फिर भी आप सूची का एक कंटेनर रखना चाहते हैं और उस स्थिति में आपको लैम्ब्डा (l-> l.myList.stream ()) का उपयोग करने की आवश्यकता हो सकती है।
मायोच

2
यदि आपको स्पष्ट कास्टिंग (उदाहरण के लिए सूची के लिए प्राथमिकताओं की सरणी) करने की आवश्यकता है, तो लैम्ब्डा आवश्यक भी हो सकती है।
माइकल फुल्टन

52

flatmap बेहतर है, लेकिन इसे प्राप्त करने के अन्य तरीके भी हैं

List<List<Object>> listOfList = ... // fill

List<Object> collect = 
      listOfList.stream()
                .collect(ArrayList::new, List::addAll, List::addAll);

37

flatMapपर विधि Streamकर सकते हैं निश्चित रूप से आप के लिए उन सूचियों समतल है, लेकिन यह बनाना होगा Streamतो एक तत्व के लिए वस्तुओं, Streamपरिणाम के लिए।

आपको उन सभी Streamवस्तुओं की आवश्यकता नहीं है । यहाँ कार्य करने के लिए सरल, संक्षिप्त कोड है।

// listOfLists is a List<List<Object>>.
List<Object> result = new ArrayList<>();
listOfLists.forEach(result::addAll);

क्योंकि एक Listहै Iterable, यह कोड विधि (जावा 8 सुविधा) को कॉल करता हैforEach , जिसे विरासत में मिला है Iterable

Iterableजब तक सभी तत्वों को संसाधित नहीं किया जाता है तब तक प्रत्येक तत्व के लिए दी गई कार्रवाई करता है या कार्रवाई एक अपवाद फेंकता है। यदि इसे निर्दिष्ट किया जाता है, तो क्रियाओं को पुनरावृत्ति के क्रम में किया जाता है।

और एक Listके Iteratorअनुक्रमिक क्रम में रिटर्न आइटम नहीं है।

के लिए Consumer, इस कोड को एक विधि संदर्भ (जावा 8 सुविधा) पूर्व जावा 8 विधि करने के लिए गुजरता List.addAllभीतरी सूची तत्वों क्रमिक रूप से जोड़ने के लिए।

इस संग्रह के अंत में निर्दिष्ट संग्रह में सभी तत्वों को जोड़ते हैं, इस क्रम में कि वे निर्दिष्ट संग्रह के इट्रेटर (वैकल्पिक संचालन) द्वारा वापस कर दिए जाते हैं।


3
अच्छा वैकल्पिक सुझाव जो कुछ अनावश्यक आवंटन से बचता है। कुछ बड़े संग्रहों के साथ काम करने के दौरान यह देखने के लिए दिलचस्प होगा कि वे एक-दूसरे की तुलना कैसे करते हैं।
प्रति लंडबर्ग

12

आप ग्रहण संग्रहflatCollect() से पैटर्न का उपयोग कर सकते हैं ।

MutableList<List<Object>> list = Lists.mutable.empty();
MutableList<Object> flat = list.flatCollect(each -> each);

यदि आप सूची से नहीं बदल सकते हैं List:

List<List<Object>> list = new ArrayList<>();
List<Object> flat = ListAdapter.adapt(list).flatCollect(each -> each);

नोट: मैं कलेक्शन एक्लिप्स का योगदानकर्ता हूं।


21
जब जावा 8 द्वारा कार्यक्षमता प्रदान की जाती है तो तीसरे पक्ष की निर्भरता का उपयोग क्यों करें?
--०३

2
ग्रहण संग्रह एपीआई संग्रह पर ही है, इसलिए कोड संक्षिप्त है, इस मामले में मुख्य कारणों में से एक है।
निखिल नानिवडेकर

11

जैसा कि @ सरवन ने उल्लेख किया है:

फ्लैटमैप बेहतर है लेकिन इसे प्राप्त करने के अन्य तरीके भी हैं

 listStream.reduce(new ArrayList<>(), (l1, l2) -> {
        l1.addAll(l2);
        return l1;
 });

योग करने के लिए, निम्नानुसार ही प्राप्त करने के कई तरीके हैं:

private <T> List<T> mergeOne(Stream<List<T>> listStream) {
    return listStream.flatMap(List::stream).collect(toList());
}

private <T> List<T> mergeTwo(Stream<List<T>> listStream) {
    List<T> result = new ArrayList<>();
    listStream.forEach(result::addAll);
    return result;
}

private <T> List<T> mergeThree(Stream<List<T>> listStream) {
    return listStream.reduce(new ArrayList<>(), (l1, l2) -> {
        l1.addAll(l2);
        return l1;
    });
}

private <T> List<T> mergeFour(Stream<List<T>> listStream) {
    return listStream.reduce((l1, l2) -> {
        List<T> l = new ArrayList<>(l1);
        l.addAll(l2);
        return l;
    }).orElse(new ArrayList<>());
}

private <T> List<T> mergeFive(Stream<List<T>> listStream) {
    return listStream.collect(ArrayList::new, List::addAll, List::addAll);
}

11

मैं बस की तरह एक और परिदृश्य व्याख्या करना चाहते हैं List<Documents>, इस सूची की तरह अन्य दस्तावेजों के कुछ और सूचियों में शामिल है List<Excel>, List<Word>, List<PowerPoint>। तो संरचना है

class A {
  List<Documents> documentList;
}

class Documents {
  List<Excel> excels;
  List<Word> words;
  List<PowerPoint> ppt;
}

अब यदि आप केवल दस्तावेजों से एक्सेल को पुनरावृत्त करना चाहते हैं, तो नीचे कुछ ऐसा करें ..

तो कोड होगा

 List<Documents> documentList = new A().getDocumentList();

 //check documentList as not null

 Optional<Excel> excelOptional = documentList.stream()
                         .map(doc -> doc.getExcel())
                         .flatMap(List::stream).findFirst();
 if(excelOptional.isPresent()){
   Excel exl = optionalExcel.get();
   // now get the value what you want.
 }

मुझे उम्मीद है कि कोडिंग के दौरान यह किसी के मुद्दे को हल कर सकता है ...


1

हम इसके लिए फ्लैटमैप का उपयोग कर सकते हैं, कृपया नीचे कोड देखें:

 List<Integer> i1= Arrays.asList(1, 2, 3, 4);
 List<Integer> i2= Arrays.asList(5, 6, 7, 8);

 List<List<Integer>> ii= Arrays.asList(i1, i2);
 System.out.println("List<List<Integer>>"+ii);
 List<Integer> flat=ii.stream().flatMap(l-> l.stream()).collect(Collectors.toList());
 System.out.println("Flattened to List<Integer>"+flat);

1

एरण के उत्तर पर एक विस्तार जो शीर्ष उत्तर था, यदि आपके पास सूचियों की परतों का एक गुच्छा है, तो आप उन्हें सपाट कर सकते हैं।

यह भी छानने का एक आसान तरीका के साथ आता है क्योंकि आप परतों के नीचे जाते हैं यदि आवश्यक हो।

उदाहरण के लिए:

List<List<List<List<List<List<Object>>>>>> multiLayeredList = ...

List<Object> objectList = multiLayeredList
    .stream()
    .flatmap(someList1 -> someList1
        .stream()
        .filter(...Optional...))
    .flatmap(someList2 -> someList2
        .stream()
        .filter(...Optional...))
    .flatmap(someList3 -> someList3
        .stream()
        .filter(...Optional...))
    ...
    .collect(Collectors.toList())

यह SQL में SELECT स्टेटमेंट्स में SELECT स्टेटमेंट्स के समान होगा।


1

विधि एक कन्वर्ट करने के List<List>लिए List:

listOfLists.stream().flatMap(List::stream).collect(Collectors.toList());

इस उदाहरण को देखें:

public class Example {

    public static void main(String[] args) {
        List<List<String>> listOfLists = Collections.singletonList(Arrays.asList("a", "b", "v"));
        List<String> list = listOfLists.stream().flatMap(List::stream).collect(Collectors.toList());

        System.out.println("listOfLists => " + listOfLists);
        System.out.println("list => " + list);
    }

}       

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

listOfLists => [[a, b, c]]
list => [a, b, c]
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.