2015-05-27 10 views
21

मैं सोच रहा हूं, उनसे पिछले n तत्वों जाओ वहाँ stream उपयोग के साथधारा

List<X> lastN = all.subList(Math.max(0, all.size() - n), all.size()); 

लिए एक विकल्प है?

+1

मुझे नहीं लगता कि यह आम तौर पर धाराओं के साथ संभव है, एक धारा के आकार के रूप में नहीं हो सकता है एक प्राथमिकता ज्ञात हो, या यह अनंत भी हो सकता है। और यदि आप किसी सूची से स्ट्रीम बनाते हैं, तो आपने जैसा ही किया है, केवल उपन्यास का उपयोग करें। –

+1

@tobias_k ओपी में एक सीमित सूची है हालांकि ... – Puce

+1

यदि आपके पास पहले से कोई सूची है, तो 'सबलिस्ट' जाने का तरीका है। फिर आप इसे कॉपी कर सकते हैं, इसे स्ट्रीम कर सकते हैं, जो कुछ भी आप चाहते हैं। –

उत्तर

19

आप इस तरह एक कस्टम कलेक्टर लिख सकते हैं:

public static <T> Collector<T, ?, List<T>> lastN(int n) { 
    return Collector.<T, Deque<T>, List<T>>of(ArrayDeque::new, (acc, t) -> { 
     if(acc.size() == n) 
      acc.pollFirst(); 
     acc.add(t); 
    }, (acc1, acc2) -> { 
     while(acc2.size() < n && !acc1.isEmpty()) { 
      acc2.addFirst(acc1.pollLast()); 
     } 
     return acc2; 
    }, ArrayList<T>::new); 
} 

और इस तरह इसका इस्तेमाल:

List<String> lastTen = input.stream().collect(lastN(10)); 
+2

आपको 'ArrayList :: new' लिखने की आवश्यकता नहीं है, केवल' ArrayList :: new' पर्याप्त है क्योंकि विधि संदर्भ हमेशा कच्चे प्रकार के बजाय टाइप अनुमान का उपयोग करते हैं (जैसे कि "हीरा ऑपरेटर" हमेशा ' :: new')। आप पहले से ही 'ArrayDeque :: new' के साथ इसका उपयोग करते हैं। Btw। मैं 'पोल फर्स्ट'/'हटाएं' को 'चुनाव फर्स्ट'/'पोलस्टास्ट' पर पसंद करूंगा ... – Holger

+2

@ होल्गर, पहले मैंने 'अरेरेलिस्ट :: नया' लिखा था, लेकिन ग्रहण ने अनचेक कन्स्ट्रक्टर के बारे में चेतावनी प्रदर्शित की थी। खैर, शायद यह एक ईसीजे-विशिष्ट समस्या है। –

+0

दिलचस्प बात यह है कि 'ArrayDeque :: new' को एक प्रकार के गवाह से फायदा होगा, क्योंकि 'ArrayDeque :: new'' कलेक्टर.ओफ़ 'कॉल अप्रचलित (और' ' पर टाइप गवाह को से सरल है , सूची > ') जबकि' ArrayList :: नया' टाइप प्रकार गवाह आवश्यक नहीं है क्योंकि इसका प्रकार लक्ष्य प्रकार से अनुमानित किया जा सकता है। – Holger

12

उपयोग Stream.skip()

धारा के पहले n तत्वों की निकालने के बाद इस धारा के शेष तत्वों से मिलकर एक धारा देता है। यदि इस स्ट्रीम में एन तत्वों से कम है तो एक खाली स्ट्रीम वापस कर दी जाएगी।

all.stream().skip(Math.max(0, all.size() - n)).forEach(doSomething); 
+0

यह अंतिम एन तत्वों को वापस नहीं करता है। यह पहली एन छोड़ देता है। ओपी ने क्या नहीं पूछा। – Bohemian

+0

@ बोहेमियन 'छोड़ें (all.size() - n)' आपको अंतिम एन तत्व देता है ... – Puce

+0

@puce हाँ ठीक है। मैं उसमें संपादित करूंगा। – Bohemian

3

मामले में धारा अज्ञात आकार की है, वहाँ शायद कोई रास्ता नहीं चारों ओर पूरे धारा लगता है और पिछले n तत्वों अब तक का सामना करना पड़ा बफरिंग है। आप इसे किसी प्रकार का डेक, या एक विशेष रिंग-बफर स्वचालित रूप से अपने अधिकतम आकार को बनाए रखने के द्वारा कर सकते हैं (कुछ कार्यान्वयन के लिए this related question देखें)।

public static <T> List<T> lastN(Stream<T> stream, int n) { 
    Deque<T> result = new ArrayDeque<>(n); 
    stream.forEachOrdered(x -> { 
     if (result.size() == n) { 
      result.pop(); 
     } 
     result.add(x); 
    }); 
    return new ArrayList<>(result); 
} 

उन कार्यों के सभी (size, pop, add) की जटिलता होना चाहिए हे (1), इसलिए साथ (अज्ञात) लंबाई एक धारा के लिए समग्र जटिलता nO (n होगा)