जावा 8 में java.util.stream.Stream से सूची प्राप्त करना


443

मैं आसानी से फ़िल्टर फ़िल्टर करने के लिए जावा 8 लैम्ब्डा के साथ खेल रहा था। लेकिन मुझे उसी विवरण के भीतर एक नई सूची के रूप में परिणाम प्राप्त करने के लिए एक संक्षिप्त तरीका नहीं मिला। यहाँ मेरा अब तक का सबसे संक्षिप्त दृष्टिकोण है:

List<Long> sourceLongList = Arrays.asList(1L, 10L, 50L, 80L, 100L, 120L, 133L, 333L);
List<Long> targetLongList = new ArrayList<>();
sourceLongList.stream().filter(l -> l > 100).forEach(targetLongList::add);

नेट पर उदाहरणों ने मेरे प्रश्न का उत्तर नहीं दिया क्योंकि वे नई परिणाम सूची तैयार किए बिना रुक जाते हैं। अधिक संक्षिप्त तरीका होना चाहिए। मैं अपेक्षा की होगी, कि Streamवर्ग तरीके के रूप में है toList(), toSet()...

क्या कोई रास्ता है कि चर targetLongListको सीधे तीसरी पंक्ति द्वारा सौंपा जा सकता है?


7
मामले में आपको सुविधा sourceLongListके Collection.removeIf(…)लिए बाद की आवश्यकता नहीं है ।
होल्गर

2
इस बारे में कैसा है? List<Long> targetLongList = sourceLongList.stream().collect(Collectors.toList());
लेययुवा

जवाबों:


609

आप जो कर रहे हैं वह सबसे सरल तरीका हो सकता है, बशर्ते कि आपकी धारा अनुक्रमिक रहे - अन्यथा आपको अनुक्रमिक () से पहले कॉल करना होगा forEach

[बाद में संपादित करें: कारण अनुक्रमिक () के लिए कॉल आवश्यक है कि कोड के रूप में यह खड़ा है ( forEach(targetLongList::add)) धारा के समानांतर होने पर racy होगा। फिर भी, यह इच्छित प्रभाव को प्राप्त नहीं करेगा, जैसा forEachकि स्पष्ट रूप से nondeterministic है - यहां तक ​​कि एक अनुक्रमिक धारा में भी तत्व प्रसंस्करण के आदेश की गारंटी नहीं है। आपको forEachOrderedसही ऑर्डर देने के लिए उपयोग करना होगा । स्ट्रीम एपीआई डिजाइनरों का इरादा यह है कि आप इस स्थिति में कलेक्टर का उपयोग नीचे की तरह करेंगे।]

एक विकल्प है

targetLongList = sourceLongList.stream()
    .filter(l -> l > 100)
    .collect(Collectors.toList());

10
जोड़: मुझे लगता है कि यदि आप एक स्थिर आयात का उपयोग करते हैं तो यह कोड थोड़ा छोटा, स्पष्ट और पूर्व हो जाता है toList। यह फ़ाइल के आयात के बीच निम्नलिखित रखकर किया जाता है static import java.util.stream.Collectors.toList;:। फिर कलेक्ट कॉल सिर्फ पढ़ता है .collect(toList())
जू

4
ग्रहण में आईडीई को विधियों के लिए एक स्थिर आयात जोड़ना संभव है। यह वरीयताएँ -> जावा -> संपादक -> सामग्री सहायता -> पसंदीदाCollectors में वर्ग को जोड़कर किया जाता है । इसके बाद, आपको केवल IDE को भरने और स्थैतिक आयात को जोड़ने के लिए हिट CTr + Space पर लिखना होगा । toLitoList
जु

3
एक बात ध्यान में रखना है कि IntStreamऔर कुछ अन्य लगभग-लेकिन-नहीं-काफी- Streamकी collect(Collector)विधि नहीं है और आपको IntStream.boxed()उन्हें नियमित रूप से Streamपहले बदलने के लिए कॉल करना होगा । तो फिर, शायद आप चाहते हैं toArray()
म्यूटेंट बॉब

हमें sequential()पहले forEachuse forEachOrdered` का उपयोग या उपयोग क्यों करना है
harish

1
@amarnathharish क्योंकि forEach समानांतर धारा के लिए ऑपरेशन निष्पादन के आदेश की गारंटी नहीं देता है। JavaDoc का कहना है, "इस ऑपरेशन का व्यवहार स्पष्ट रूप से nondeterministic है। समानांतर स्ट्रीम पाइपलाइनों के लिए, यह ऑपरेशन स्ट्रीम के एनकाउंटर ऑर्डर का सम्मान करने की गारंटी नहीं देता है, क्योंकि ऐसा करने से समानता का लाभ मिलता है।" (इस उद्धरण का पहला वाक्य वास्तव में इसका मतलब है कि क्रमिक धाराओं के लिए आदेश की गारंटी नहीं है, हालांकि व्यवहार में इसे संरक्षित किया गया है।)
मौरिस नाफ्टलिन

183

अपडेट किया गया:

एक और तरीका है Collectors.toList:

targetLongList = 
    sourceLongList.stream().
    filter(l -> l > 100).
    collect(Collectors.toList());

पिछला समाधान:

एक और तरीका है Collectors.toCollection:

targetLongList = 
    sourceLongList.stream().
    filter(l -> l > 100).
    collect(Collectors.toCollection(ArrayList::new));

60
हालाँकि, यह उपयोगी है यदि आप एक विशेष सूची कार्यान्वयन चाहते हैं।
orbfish

1
इंटरफेस के खिलाफ कोड करने की सिफारिश करने के बावजूद, स्पष्ट मामले हैं (उनमें से एक GWT होने के नाते) जब आपको ठोस कार्यान्वयन के खिलाफ कोड करना होता है (जब तक कि आप सभी सूची कार्यान्वयन को संकलित और जावास्क्रिप्ट के रूप में वितरित नहीं करना चाहते)।
एडुआर्ड कोरेन्शी 14

3
इस विधि के लिए एक अन्य समर्थक, Collectors::toListjavadoc से: "सूची के प्रकार, परिवर्तनशीलता, क्रमबद्धता या थ्रेड-सुरक्षा पर कोई गारंटी नहीं है; यदि लौटे सूची पर अधिक नियंत्रण आवश्यक है, तो उपयोग करें toCollection(Supplier)।"
चार्ल्स वुड

12

मैं एक उपयोग विधि का उपयोग करना पसंद करता हूं जो कि ArrayListजब मैं चाहता हूं तब के लिए एक कलेक्टर लौटाता हूं।

मुझे लगता है कि इस Collectors.toCollection(ArrayList::new)तरह के एक आम ऑपरेशन के लिए समाधान का उपयोग थोड़ा बहुत शोर है।

उदाहरण:

ArrayList<Long> result = sourceLongList.stream()
    .filter(l -> l > 100)
    .collect(toArrayList());

public static <T> Collector<T, ?, ArrayList<T>> toArrayList() {
    return Collectors.toCollection(ArrayList::new);
}

इस उत्तर के साथ, मैं यह भी प्रदर्शित करना चाहता हूं कि कस्टम कलेक्टरों को बनाना और उनका उपयोग करना कितना सरल है, जो आम तौर पर बहुत उपयोगी है।


यदि आप सूची को <लॉन्ग> के रूप में परिणाम घोषित करते हैं, तो आपको इस उपयोग विधि का उपयोग करने की आवश्यकता नहीं है। संग्राहक.toList करेगा इसके अलावा, इंटरफेस के बजाय विशिष्ट कक्षाओं का उपयोग करना एक कोड गंध है।
लुलिस मार्टिनेज

1
@LluisMartinez: "कलेक्टर .toList करेंगे।" : नहीं, कई स्थितियों में नहीं। क्योंकि toListयदि आप उदाहरण के लिए कार्यक्रम में बाद में सूची को संशोधित करना चाहते हैं तो इसका उपयोग करना अच्छा नहीं है । toListप्रलेखन इस कहते हैं: "प्रकार, अस्थिरता, serializability, या सूची के धागे की सुरक्षा लौटे पर कोई गारंटी रहे हैं, अगर लौटे सूची पर अधिक नियंत्रण की आवश्यकता है, उपयोग toCollection।" । मेरा जवाब एक सामान्य मामले में ऐसा करने के लिए इसे और अधिक सुविधाजनक बनाने का तरीका दर्शाता है।
Lii

यदि आप विशेष रूप से एक ArrayList बनाना चाहते हैं तो यह ठीक है।
लुलिस मार्टिनेज

5

यदि आपके पास प्राथमिकताओं की एक सरणी है, तो आप ग्रहण संग्रह में उपलब्ध आदिम संग्रहों का उपयोग कर सकते हैं ।

LongList sourceLongList = LongLists.mutable.of(1L, 10L, 50L, 80L, 100L, 120L, 133L, 333L);
LongList targetLongList = sourceLongList.select(l -> l > 100);

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

List<Long> sourceLongList = Arrays.asList(1L, 10L, 50L, 80L, 100L, 120L, 133L, 333L);
List<Long> targetLongList = 
    ListAdapter.adapt(sourceLongList).select(l -> l > 100, new ArrayList<>());

यदि आप उपयोग करना चाहते हैं LongStream:

long[] sourceLongs = new long[]{1L, 10L, 50L, 80L, 100L, 120L, 133L, 333L};
LongList targetList = 
    LongStream.of(sourceLongs)
    .filter(l -> l > 100)
    .collect(LongArrayList::new, LongArrayList::add, LongArrayList::addAll);

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


4

थोड़ा और अधिक कुशल तरीका (स्रोत सूची बनाने और फ़िल्टर द्वारा ऑटो-अनबॉक्सिंग से बचें):

List<Long> targetLongList = LongStream.of(1L, 10L, 50L, 80L, 100L, 120L, 133L, 333L)
    .filter(l -> l > 100)
    .boxed()
    .collect(Collectors.toList());


1

यदि आप तृतीय पक्ष पुस्तकालयों का उपयोग करने में कोई आपत्ति नहीं करते हैं, तो एओएल के साइक्लोप्स-रिएक्शन लिबास (प्रकटीकरण मैं एक योगदानकर्ता है) में सूची सहित सभी जेडीके संग्रह प्रकारों के लिए एक्सटेंशन हैं । ListX इंटरफ़ेस java.util.List को विस्तारित करता है और बड़ी संख्या में उपयोगी ऑपरेटरों को जोड़ता है, जिसमें फ़िल्टर भी शामिल है।

आप बस लिख सकते हैं-

ListX<Long> sourceLongList = ListX.of(1L, 10L, 50L, 80L, 100L, 120L, 133L, 333L);
ListX<Long> targetLongList = sourceLongList.filter(l -> l > 100);

ListX को एक मौजूदा सूची (ListX.fromIterable के माध्यम से) से भी बनाया जा सकता है


1

लॉन्गस्ट्रीम क्लास द्वारा प्रदान की गई विधि का एक और संस्करण है और इसी तरह इंटस्ट्रीम और डबलस्ट्रीम कक्षाओं द्वारा भी।

<R> R collect(Supplier<R> supplier,
              ObjLongConsumer<R> accumulator,
              BiConsumer<R,R> combiner)

इस स्ट्रीम के तत्वों पर एक परिवर्तनशील कमी ऑपरेशन करता है। एक परिवर्तनशील कमी वह है जिसमें कम किया गया मूल्य एक उत्परिवर्तित परिणाम कंटेनर होता है, जैसे कि ArrayList, और तत्वों को परिणाम को प्रतिस्थापित करने के बजाय परिणाम की स्थिति को अपडेट करके शामिल किया जाता है। यह इसके बराबर परिणाम देता है:

R result = supplier.get();
  for (long element : this stream)
       accumulator.accept(result, element);
  return result;

कम (लंबे, LongBinaryOperator) की तरह, अतिरिक्त सिंक्रनाइज़ेशन की आवश्यकता के बिना ऑपरेशन को इकट्ठा किया जा सकता है। यह एक टर्मिनल ऑपरेशन है।

और इस संग्रह विधि के साथ आपके प्रश्न का उत्तर नीचे दिया गया है:

    LongStream.of(1L, 2L, 3L, 3L).filter(i -> i > 2)
    .collect(ArrayList::new, (list, value) -> list.add(value)
    , (list1, list2) -> list1.addAll(list2));

नीचे विधि संदर्भ प्रकार दिया गया है जो काफी स्मार्ट है लेकिन कुछ को समझने में मुश्किल है:

     LongStream.of(1L, 2L, 3L, 3L).filter(i -> i > 2)
    .collect(ArrayList::new, List::add , List::addAll);

नीचे हैशसेट संस्करण होगा:

     LongStream.of(1L, 2L, 3L, 3).filter(i -> i > 2)
     .collect(HashSet::new, HashSet::add, HashSet::addAll);

इसी तरह लिंक्डलिस्ट संस्करण इस प्रकार है:

     LongStream.of(1L, 2L, 3L, 3L)
     .filter(i -> i > 2)
     .collect(LinkedList::new, LinkedList::add, LinkedList::addAll);

0

किसी के मामले में (मेरे जैसा) बाहर आदिम प्रकार के बजाय वस्तुओं से निपटने के तरीकों की तलाश कर रहा है mapToObj()

String ss = "An alternative way is to insert the following VM option before "
        + "the -vmargs option in the Eclipse shortcut properties(edit the "
        + "field Target inside the Shortcut tab):";

List<Character> ll = ss
                        .chars()
                        .mapToObj(c -> new Character((char) c))
                        .collect(Collectors.toList());

System.out.println("List type: " + ll.getClass());
System.out.println("Elem type: " + ll.get(0).getClass());
ll.stream().limit(50).forEach(System.out::print);

प्रिंट:

List type: class java.util.ArrayList
Elem type: class java.lang.Character
An alternative way is to insert the following VM o

0
String joined = 
                Stream.of(isRead?"read":"", isFlagged?"flagged":"", isActionRequired?"action":"", isHide?"hide":"")
                      .filter(s -> s != null && !s.isEmpty())
                      .collect(Collectors.joining(","));

0

यहाँ AbacusUtil द्वारा कोड दिया गया है

LongStream.of(1, 10, 50, 80, 100, 120, 133, 333).filter(e -> e > 100).toList();

प्रकटीकरण il मैं AbacusUtil का डेवलपर हूं।


मुझे लोंगस्ट्रीम क्लास में मौजूद कोई भी विधि नहीं मिली है। क्या आप यह कोड चला सकते हैं?
विनीत कटारिया

@VaneetKataria कोशिश करो com.landawn.abacus.util.stream.LongStreamया LongStreamExAbacusUtil में
user_3380739

0

आप नीचे दिए गए कोड को फिर से लिख सकते हैं:

List<Long> sourceLongList = Arrays.asList(1L, 10L, 50L, 80L, 100L, 120L, 133L, 333L);
List<Long> targetLongList = sourceLongList.stream().filter(l -> l > 100).collect(Collectors.toList());

आपके सहयोग के लिए धन्यवाद। हालाँकि, कृपया बताएं कि आपने क्या बदला है और यह प्रश्न से कितना दूर है।
बी - रियान

यहाँ सबसे पहले मैंने अपने ArrayList को आवश्यक डेटा के फ़िल्टर I फ़िल्टर का उपयोग करके उन्हें भाप में परिवर्तित किया। अंत में मैंने java 8 स्ट्रीम के कलेक्ट मेथड का इस्तेमाल किया है ताकि नई लिस्ट में डेटा कलेक्ट किया जा सके जिसे लक्ष्यलॉन्गलिस्ट कहा जाता है।
प्रतीक पवार

0

एक परिवर्तनशील सूची में एकत्र करने के लिए:

targetList = sourceList.stream()
                       .filter(i -> i > 100) //apply filter
                       .collect(Collectors.toList());

एक अपरिवर्तनीय सूची में एकत्र करने के लिए:

targetList = sourceList.stream()
                       .filter(i -> i > 100) //apply filter
                       .collect(Collectors.toUnmodifiableList());

JavaDoccollect से स्पष्टीकरण :

एक कलेक्टर का उपयोग करके इस धारा के तत्वों पर एक परिवर्तनशील कमी संचालन करता है। एक संग्रहकर्ता (संग्रहकर्ता, BiConsumer, BiConsumer) को इकट्ठा करने के लिए तर्क के रूप में उपयोग किए जाने वाले कार्यों को एकत्रित करता है, जो संग्रह की रणनीतियों के पुन: उपयोग और कई-स्तरीय समूह या विभाजन जैसे संग्रह कार्यों की संरचना की अनुमति देता है। यदि धारा समानांतर है, और कलेक्टर समवर्ती है, और या तो धारा अनियंत्रित है या कलेक्टर अनियंत्रित है, तो एक समवर्ती कमी का प्रदर्शन किया जाएगा (समवर्ती कमी पर विवरण के लिए कलेक्टर देखें।)

यह एक टर्मिनल ऑपरेशन है।

जब समानांतर में निष्पादित किया जाता है, तो कई मध्यवर्ती परिणाम त्वरित, आबाद, और विलय हो सकते हैं ताकि उत्परिवर्तित डेटा संरचनाओं के अलगाव को बनाए रखा जा सके। इसलिए, जब भी गैर-थ्रेड-सुरक्षित डेटा संरचनाओं (जैसे ArrayList) के साथ समानांतर में निष्पादित किया जाता है, तो समानांतर कमी के लिए कोई अतिरिक्त सिंक्रनाइज़ेशन की आवश्यकता नहीं होती है।


-3

यदि आप इसका उपयोग नहीं करते हैं तो parallel()यह काम करेगा

List<Long> sourceLongList = Arrays.asList(1L, 10L, 50L, 80L, 100L, 120L, 133L, 333L);

List<Long> targetLongList =  new ArrayList<Long>();

sourceLongList.stream().peek(i->targetLongList.add(i)).collect(Collectors.toList());

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

यह कॉल करने के लिए बहुत अजीब है collectऔर फिर रिटर्न वैल्यू को सेव नहीं करता है। उस स्थिति में आप forEachइसके बजाय उपयोग कर सकते हैं । लेकिन यह अभी भी एक गरीब समाधान है।
Lii

1
इस तरह से झांकना () का उपयोग करना एक एंटीपैटर्न है।
ग्रेजेगोरज पिवोवारेक जूल

स्ट्रीम जावा डॉक्स पेकिंग विधि के अनुसार केवल डीबगिंग उद्देश्यों के लिए उपयोग किया जाना चाहिए। इसे डीबगिंग के अलावा किसी भी प्रसंस्करण के लिए उपयोग नहीं किया जाना चाहिए।
विनीत कटारिया
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.