java stream group by and find top 10 in one iteration

It defers from this How to apply sorting and limiting after groupby using Java streams because I want to solve this problem in exactly one iterations

Imagine I have following entity:

public static class Hospital {     private AREA area;     private int patients;      public Hospital(AREA area, int patients) {         this.area = area;         this.patients = patients;     }      public AREA getArea() {         return area;     }      public void setArea(AREA area) {         this.area = area;     }      public int getPatients() {         return patients;     }      public void setPatients(int patients) {         this.patients = patients;     } }  public enum AREA {     AREA1,     AREA2,     AREA3 } 

Now given a list of hospitals I want to find areas with most patients in them, here’s what I have done so far:

public static void main(String[] args) {     List<Hospital> list = Arrays.asList(             new Hospital(AREA.AREA1, 20),             new Hospital(AREA.AREA2, 10),             new Hospital(AREA.AREA1, 10),             new Hospital(AREA.AREA3, 40),             new Hospital(AREA.AREA2, 10));     Map<AREA, Integer> map = findTopTen(list);     for (AREA area : map.keySet())         System.out.println(area);  }  public static Map<AREA, Integer> findTopTen(Iterable<Hospital> iterable) {     Map<AREA, Integer> map = StreamSupport.stream(iterable.spliterator(), false)             .collect(Collectors.groupingBy(Hospital::getArea,                     Collectors.summingInt(Hospital::getPatients)));     for (Map.Entry<AREA, Integer> area : map.entrySet())         System.out.println(area.getKey() + "...." + area.getValue());     return map.entrySet().stream()             .sorted((e1, e2) -> e2.getValue() - e1.getValue())             .collect(Collectors.toMap(Map.Entry::getKey,                     Map.Entry::getValue, (o, o2) -> o,                     LinkedHashMap::new));  } 

Clearly I’ve Iterated two times in order to find top ten areas with most patients in them( once for grouping hospital by area and calculate summation for that group and once more for finding top ten areas).

Now what I want to know is:

1) Is there any better approach to solve this problem in one stream and therefore one iteration?

2) Is there any performance benefit for doing it in one iteration, what is the best practice for solving this kind of problem?(In my point of view on one hand when I call collect which is a terminal operation first time it iterates my iterable and saves the intermediate result in another object, in my code I named that object iterationOneResult, so using one stream and calling collect one time will omit that intermediate result which is the main benefit of using stream in java on the other hand solving this problem in one iteration reduce complexity from O(2n) to O(n))

Add Comment
1 Answer(s)

This can hardly be done in one iteration using stream, but could be more concise using one stream chain

Map<AREA, Integer> map = list.stream()         .collect(Collectors.groupingBy(Hospital::getArea, Collectors.summingInt(Hospital::getPatients)))         .entrySet().stream()         .sorted(Map.Entry.comparingByValue(Comparator.reverseOrder()))         .limit(10)         .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); 

Also if you want to print intermediate result (just for debugging purposes), you could insert

.peek(e -> System.out.println(e.getKey() + " " + e.getValue())) 

rigth after .entrySet().stream()

Answered on July 16, 2020.
Add Comment

Your Answer

By posting your answer, you agree to the privacy policy and terms of service.