Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java 8 is not maintaining the order while grouping

I m using Java 8 for grouping by data. But results obtained are not in order formed.

Map<GroupingKey, List<Object>> groupedResult = null;          if (!CollectionUtils.isEmpty(groupByColumns)) {              Map<String, Object> mapArr[] = new LinkedHashMap[mapList.size()];              if (!CollectionUtils.isEmpty(mapList)) {                 int count = 0;                 for (LinkedHashMap<String, Object> map : mapList) {                     mapArr[count++] = map;                 }             }             Stream<Map<String, Object>> people = Stream.of(mapArr);             groupedResult = people                     .collect(Collectors.groupingBy(p -> new GroupingKey(p, groupByColumns), Collectors.mapping((Map<String, Object> p) -> p, toList())));   public static class GroupingKey           public GroupingKey(Map<String, Object> map, List<String> cols) {              keys = new ArrayList<>();              for (String col : cols) {                 keys.add(map.get(col));             }         }          // Add appropriate isEqual() ... you IDE should generate this         @Override         public boolean equals(Object obj) {             if (obj == null) {                 return false;             }             if (getClass() != obj.getClass()) {                 return false;             }             final GroupingKey other = (GroupingKey) obj;             if (!Objects.equals(this.keys, other.keys)) {                 return false;             }             return true;         }          @Override         public int hashCode() {             int hash = 7;             hash = 37 * hash + Objects.hashCode(this.keys);             return hash;         }          @Override         public String toString() {             return keys + "";         }          public ArrayList<Object> getKeys() {             return keys;         }          public void setKeys(ArrayList<Object> keys) {             this.keys = keys;         }      } 

Here i am using my class groupingKey by which i m dynamically passing from ux. How can get this groupByColumns in sorted form?

like image 867
Shreya Shah Avatar asked Feb 27 '15 11:02

Shreya Shah


People also ask

Does Groupby preserve order Java?

java - Stream doesn't preserve the order after grouping - Stack Overflow. Stack Overflow for Teams – Start collaborating and sharing organizational knowledge.

Does Java 8 stream maintain order?

If you have an ordered stream and perform operations which guarantee to maintain the order, it doesn't matter whether the stream is processed in parallel or sequential; the implementation will maintain the order. The ordered property is distinct from parallel vs sequential.

Does stream Map maintain order?

A parallel stream is performed one or more elements at a time. Thus the map() would preserve the encounter of the stream order but not the original List's order.


2 Answers

Not maintaining the order is a property of the Map that stores the result. If you need a specific Map behavior, you need to request a particular Map implementation. E.g. LinkedHashMap maintains the insertion order:

groupedResult = people.collect(Collectors.groupingBy(     p -> new GroupingKey(p, groupByColumns),     LinkedHashMap::new,     Collectors.mapping((Map<String, Object> p) -> p, toList()))); 

By the way, there is no reason to copy the contents of mapList into an array before creating the Stream. You may simply call mapList.stream() to get an appropriate Stream.

Further, Collectors.mapping((Map<String, Object> p) -> p, toList()) is obsolete. p->p is an identity mapping, so there’s no reason to request mapping at all:

groupedResult = mapList.stream().collect(Collectors.groupingBy(     p -> new GroupingKey(p, groupByColumns), LinkedHashMap::new, toList())); 

But even the GroupingKey is obsolete. It basically wraps a List of values, so you could just use a List as key in the first place. Lists implement hashCode and equals appropriately (but you must not modify these key Lists afterwards).

Map<List<Object>, List<Object>> groupedResult=   mapList.stream().collect(Collectors.groupingBy(     p -> groupByColumns.stream().map(p::get).collect(toList()),     LinkedHashMap::new, toList())); 
like image 193
Holger Avatar answered Sep 19 '22 12:09

Holger


Based on @Holger's great answer. I post this to help those who want to keep the order after grouping as well as changing the mapping.

Let's simplify and suppose we have a list of persons (int age, String name, String adresss...etc) and we want the names grouped by age while keeping ages in order:

final LinkedHashMap<Integer, List<String> map = myList                 .stream()                 .sorted(Comparator.comparing(p -> p.getAge())) //sort list by ages                 .collect(Collectors.groupingBy(p -> p.getAge()),                         LinkedHashMap::new, //keeps the order                         Collectors.mapping(p -> p.getName(), //map name                                 Collectors.toList()))); 
like image 34
hzitoun Avatar answered Sep 17 '22 12:09

hzitoun