2015-11-22 4 views
14

मैं प्रत्येक प्रविष्टि द्वारा समूह को कैसे सीमित कर सकता हूं?सीमा समूह में जावा 8

उदाहरण के लिए (: stream groupBy इस उदाहरण के आधार पर):

studentClasses.add(new StudentClass("Kumar", 101, "Intro to Web")); 
studentClasses.add(new StudentClass("White", 102, "Advanced Java")); 
studentClasses.add(new StudentClass("Kumar", 101, "Intro to Cobol")); 
studentClasses.add(new StudentClass("White", 101, "Intro to Web")); 
studentClasses.add(new StudentClass("White", 102, "Advanced Web")); 
studentClasses.add(new StudentClass("Sargent", 106, "Advanced Web")); 
studentClasses.add(new StudentClass("Sargent", 103, "Advanced Web")); 
studentClasses.add(new StudentClass("Sargent", 104, "Advanced Web")); 
studentClasses.add(new StudentClass("Sargent", 105, "Advanced Web")); 

इस विधि सरल समूह वापसी:

Map<String, List<StudentClass>> groupByTeachers = studentClasses 
      .stream().collect(
        Collectors.groupingBy(StudentClass::getTeacher)); 

क्या होगा यदि मैं वापस आ संग्रह सीमित करने के लिए करना चाहते हैं? मान लीजिए कि मैं प्रत्येक शिक्षक के लिए केवल प्रथम एन कक्षा चाहता हूं। यह कैसे किया जा सकता है?

+3

क्या आप पहली बार ?, मतलब है आपको सबसे कम वर्ग संख्या, ASCIIBetically न्यूनतम नाम, या किसी यादृच्छिक चयन के साथ कक्षाओं का मतलब क्या एन कक्षाओं के। नोट: कक्षाओं का सेट अनियंत्रित हो सकता है। –

+0

@ पीटर Lawrey आप सही हैं, मैंने इसका उल्लेख नहीं किया है, मेरे लिए आदेश अप्रासंगिक है, लेकिन अगर हम अधिक गहन और सामान्य समाधान चाहते हैं - बीमार खुश रहें यदि आप एक सॉर्टिंग उदाहरण जोड़ते हैं (फ़ील्ड में से एक) – yossico

उत्तर

15

यह संभव होगा कि परिणामी सूची में तत्वों की संख्या सीमित करता है।

यह संग्राहक सूची के प्रमुख तत्वों को बनाए रखेगा (in encounter order)। संग्रह के दौरान सीमा तक पहुंचने पर संचयक और संयोजक प्रत्येक तत्व को फेंक देते हैं। Combiner कोड थोड़ा मुश्किल है लेकिन इसका लाभ यह है कि बाद में फेंकने के लिए कोई अतिरिक्त तत्व जोड़ा नहीं जाता है।

private static <T> Collector<T, ?, List<T>> limitingList(int limit) { 
    return Collector.of(
       ArrayList::new, 
       (l, e) -> { if (l.size() < limit) l.add(e); }, 
       (l1, l2) -> { 
        l1.addAll(l2.subList(0, Math.min(l2.size(), Math.max(0, limit - l1.size())))); 
        return l1; 
       } 
      ); 
} 

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

Map<String, List<StudentClass>> groupByTeachers = 
     studentClasses.stream() 
        .collect(groupingBy(
          StudentClass::getTeacher, 
          limitingList(2) 
        )); 
4

इसके लिए आपको अपने मानचित्र के परिणाम .stream() की आवश्यकता है। आप यह कर कर ऐसा कर सकते हैं:

// Part that comes from your example 
Map<String, List<StudentClass>> groupByTeachers = studentClasses 
      .stream().collect(
        Collectors.groupingBy(StudentClass::getTeacher)); 

// Create a new stream and limit the result 
groupByTeachers = 
    groupByTeachers.entrySet().stream() 
     .limit(N) // The actual limit 
     .collect(Collectors.toMap(
      e -> e.getKey(), 
      e -> e.getValue() 
     )); 

यह ऐसा करने का एक बहुत ही आसान तरीका नहीं है। लेकिन अगर आप प्रारंभिक सूची में .limit(), तो समूह के परिणाम गलत होंगे। सीमा की गारंटी देने का यह सबसे सुरक्षित तरीका है।

संपादित करें:

के रूप में टिप्पणी इस शिक्षक, नहीं प्रति शिक्षक वर्ग की सीमा में कहा गया है। उस मामले में आप कर सकते हैं:

groupByTeachers = 
     groupByTeachers.entrySet().stream() 
      .collect(Collectors.toMap(
       e -> e.getKey(), 
       e -> e.getValue().stream().limit(N).collect(Collectors.toList()) // Limit the classes PER teacher 
      )); 
+0

बहुत नहीं इष्टतम, मुझे लगता है कि वह प्रारंभिक समूह में ऐसा करने का मतलब था। –

+0

यह शिक्षकों की संख्या को सीमित करता है, प्रति शिक्षक कक्षाओं की संख्या नहीं। – siegi

+3

'Map.replaceAll' का उपयोग प्रत्येक तत्व के लिए एक अलग स्ट्रीम करने की तुलना में पोस्ट-प्रोसेसिंग चरण में बेहतर होगा। लेकिन @ तुनाकी का जवाब वैसे भी बेहतर है। –

3

यह आपको इच्छित परिणाम देना होगा, लेकिन यह अभी भी धारा के सभी तत्वों को categorizes: एक नए कलेक्टर को पेश करने

final int N = 10; 
final HashMap<String, List<StudentClass>> groupByTeachers = 
     studentClasses.stream().collect(
      groupingBy(StudentClass::getTeacher, HashMap::new, 
       collectingAndThen(toList(), list -> list.subList(0, Math.min(list.size(), N))))); 
4

आप collectingAndThen इस्तेमाल कर सकते हैं, जिसके परिणामस्वरूप सूची पर एक फिनिशर आपरेशन को परिभाषित करने के। इस तरह से आप सीमित कर सकते हैं, फिल्टर, प्रकार, ... सूचियां:

int limit = 2; 

Map<String, List<StudentClass>> groupByTeachers = 
    studentClasses.stream() 
        .collect(
         groupingBy(
          StudentClass::getTeacher, 
          collectingAndThen(
           toList(), 
           l -> l.stream().limit(limit).collect(toList())))); 
+0

यह अभी भी नक्शे में पहले से जोड़े जाने के बाद मानों को फ़िल्टर कर रहा है, लेकिन अब तक का सबसे अच्छा जवाब है। –

+2

फिनिशर का विचार अच्छा है लेकिन फिनिशर में ओ (एन) लागत की कोई आवश्यकता नहीं है। आप 'सूची -> list.size() <= सीमा जैसी कुछ कर सकते हैं?सूची: list.subList (0, सीमा)) 'इसके बजाए। लेकिन मैं अभी भी तुनाकी के समाधान को पसंद करता हूं, जिसकी सूची में अतिरिक्त तत्वों को चिपकाने की आवश्यकता नहीं है। –

+0

कौन इस तरह कोड ?? –