2014-04-07 6 views
21

पिछले प्रश्न में [How to dynamically do filtering in Java 8?] स्टुअर्ट मार्क्स ने एक अद्भुत जवाब दिया, और धारा से शीर्ष और शीर्ष पर आधारित के चयन को संभालने के लिए कई उपयोगी उपयोगिताओं प्रदान की।Java 8 lambda का उपयोग कर स्ट्रीम से आइटम्स की एक श्रृंखला कैसे प्राप्त करें?

मैं उन्हें अपने मूल जवाब से यहां शामिल करेंगे:

@FunctionalInterface 
public interface Criterion { 
    Stream<Widget> apply(Stream<Widget> s); 
} 

Criterion topN(Comparator<Widget> cmp, long n) { 
    return stream -> stream.sorted(cmp).limit(n); 
} 

Criterion topPercent(Comparator<Widget> cmp, double pct) { 
    return stream -> { 
     List<Widget> temp = 
      stream.sorted(cmp).collect(toList()); 
     return temp.stream() 
        .limit((long)(temp.size() * pct)); 
    }; 
} 

मेरे यहाँ प्रश्न हैं:

[1] कैसे की निश्चित राशि के साथ एक धारा से 7 के लिए 3 से शीर्ष आइटम प्राप्त करने आइटम है, तो धारा A1, A2 .. A10,

topNFromRange(Comparator<Widget> cmp, long from, long to) = topNFromRange(comparing(Widget::length), 3L, 7L) 

करने के लिए कॉल वापस आ जाएगी {A3, A4, A5, A6, ए 7} से

+०१२३५१६४१०६१ आइटम नहीं है अगर

सबसे सरल तरीका मैं सोच सकता हूं कि मूल से शीर्ष 7 [टी 7] प्राप्त करें, मूल से शीर्ष 3 [टी 3] प्राप्त करें, और फिर टी 7 - टी 3 प्राप्त करें।

[2] कैसे मदों की निश्चित राशि के साथ एक धारा से 30% ऊपर शीर्ष 10% से ऊपर आइटम प्राप्त करने, इसलिए धारा एक्स 1 से आइटम है, तो X2 .. X100,

topPercentFromRange(Comparator<Widget> cmp, double from, double to) = topNFromRange(comparing(Widget::length), 0.10, 0.30) 
करने के लिए कॉल

{X10, X11, X12, ..., X29, X30} वापस आ जाएगी

सबसे आसान तरीका मैं के बारे में सोच सकते हैं पाने के शीर्ष 30% [TP30] मूल से, मिल शीर्ष 10% है [TP10 ] मूल से, और फिर टीपी 30 - टीपी 10 प्राप्त करें।

उपरोक्त स्थितियों को संक्षेप में व्यक्त करने के लिए जावा 8 लैम्ब्डा का उपयोग करने के कुछ बेहतर तरीके क्या हैं?

उत्तर

19

उपयोगकर्ता skiwi पहले से ही answered प्रश्न का पहला हिस्सा है।दूसरा हिस्सा है:

(2) कैसे मदों की निश्चित राशि के साथ एक धारा से 30% ऊपर शीर्ष 10% से ऊपर आइटम प्राप्त करने ....

ऐसा करने के लिए, आप अन्य प्रश्नों के लिए मेरे answer में topPercent जैसी ही तकनीक का उपयोग करना होगा। यही है, कुछ तत्वों को फ़िल्टर करने के बाद, तत्वों की गिनती प्राप्त करने में सक्षम होने के लिए आपको तत्वों को एक सूची में एकत्र करना होगा।

एक बार जब आप गिनती कर लेंगे, तो आप गिनती और प्रतिशत के आधार पर skip और limit के लिए सही मानों की गणना करें। कुछ इस तरह काम कर सकते हैं:

Criterion topPercentFromRange(Comparator<Widget> cmp, double from, double to) { 
    return stream -> { 
     List<Widget> temp = 
      stream.sorted(cmp).collect(toList()); 
     return temp.stream() 
        .skip((long)(temp.size() * from)) 
        .limit((long)(temp.size() * (to - from))); 
    }; 
} 

बेशक आप त्रुटि from और to पर जाँच करना होगा। एक और सूक्ष्म समस्या यह निर्धारित कर रही है कि कितने तत्व उत्सर्जित करते हैं। उदाहरण के लिए, यदि आपके पास दस तत्व हैं, तो वे इंडेक्स [0..9] पर हैं, जो 0%, 10%, 20%, ..., 90% के अनुरूप हैं। लेकिन अगर आप 9% से 11% तक की रेंज मांगना चाहते थे, तो उपर्युक्त कोड कोई तत्व नहीं छोड़ेगा, न कि 10% पर एक जैसा कि आप उम्मीद कर सकते हैं। इसलिए प्रतिशत कंप्यूटेशंस के साथ कुछ झुकाव शायद आप जो करने की कोशिश कर रहे हैं उसके अर्थशास्त्र को फिट करने के लिए आवश्यक है।

+0

जो कुछ मैं ढूंढ रहा था उसके लिए पर्याप्त बंद करें, मैं विवरण तैयार करूंगा, धन्यवाद! – Frank

+0

मैंने अपना जवाब अपडेट किया है जिसमें आप जो भी कर रहे हैं उसका एक रूप भी शामिल कर सकते हैं, लेकिन फिर कलेक्टरों का उपयोग करके, शायद यह मानदंडों के मूल प्रश्न के लिए भी दिलचस्प हो सकता है? – skiwi

+0

@skiwi संग्रह को संग्रह में बदलने के लिए एक कलेक्टर के फिनिशर फ़ंक्शन का उपयोग करके दिलचस्प है। मुझे यकीन नहीं है कि यह एक स्थानीय चर घोषित करने की तुलना में बेहतर या बदतर है। (लैम्बडा पैरामीटर इस मामले में एक स्थानीय की तरह प्रयोग किया जाता है।) हालांकि, भविष्य के लिए ध्यान में रखना एक उपयोगी तकनीक है। –

21

एक Stream<T> से एक सीमा के लिए, आप skip(long n) का उपयोग पहले तत्वों की एक निर्धारित संख्या को छोड़ कर सकते हैं, और फिर आप के लिए limit(long n) फोन केवल आइटम की एक विशेष राशि ले सकते हैं।

10 तत्वों के साथ एक धारा पर विचार करें, तो 3 से 7 तत्वों प्राप्त करने के लिए, आप सामान्य रूप से एक List से कहेंगे: एक Stream साथ

list.subList(3, 7); 

अब, आप पहले 3 आइटम को छोड़ने के लिए की जरूरत है, और फिर ले 7 - 3 = 4 आइटम, तो यह हो जाता है:

stream.skip(3).limit(4); 

दूसरा जवाब देने के लिए @StuartMarks 'समाधान के लिए एक प्रकार के रूप में, मैं आप निम्नलिखित समाधान जो श्रृंखला बरकरार करने के लिए संभावना छोड़ देता है प्रदान करेंगे, यह समान काम करता है कैसे @StuartMarks यह करता है:

private <T> Collector<T, ?, Stream<T>> topPercentFromRangeCollector(Comparator<T> comparator, double from, double to) { 
    return Collectors.collectingAndThen(
     Collectors.toList(), 
     list -> list.stream() 
      .sorted(comparator) 
      .skip((long)(list.size() * from)) 
      .limit((long)(list.size() * (to - from))) 
    ); 
} 

और

IntStream.range(0, 100) 
     .boxed() 
     .collect(topPercentFromRangeCollector(Comparator.comparingInt(i -> i), 0.1d, 0.3d)) 
     .forEach(System.out::println); 

यह तत्व 10 29.

यह एक Collector<T, ?, Stream<T>> कि धारा से अपने तत्वों में ले जाता है, उन्हें एक List<T> में बदल का उपयोग करके काम करता है के माध्यम से है, तो प्रिंट होगा Stream<T> प्राप्त करता है, इसे टाइप करता है और इसमें (सही) सीमाएं लागू करता है।

+0

यदि आप पहले 10% आइटम छोड़ते हैं, तो धारा में केवल 9 0% आइटम शेष हैं, मूल 30% से आइटम कैसे प्राप्त करें, क्योंकि 90% से 30% मूल 30% नहीं है , क्या मैं सही हूँ ? – Frank

+1

@ फ्रैंक आपको पहले से ही उन नंबरों की गणना करने की आवश्यकता होगी। – skiwi

+0

ठीक है, धन्यवाद! – Frank

संबंधित मुद्दे

 संबंधित मुद्दे