43

I'm using Java 8 for grouping by data. But the results obtained are not in the 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?

2 Answers 2

73

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 unnecessary. 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())); 
Sign up to request clarification or add additional context in comments.

5 Comments

Thanx Holger u made my task vry simpler. But still i have issue that if i want to apply sorting in this only wid this groupedColumns then wat should i do?
The method toList() is undefined, is it Collections.toList?
@geneb. Collectors.toList(). You may use import static java.util.stream.Collectors.*; to avoid repetitions of Collectors., when combining collectors.
"Collectors.mapping((Map<String, Object> p) -> p, toList()) is obsolete." — I don't think "obsolete" is the right term, as that implies that it was necessary but is no longer. Maybe "unnecessary"?
@M.Justin interesting. I thought it could also be used like redundant or superfluous but apparently, the implication of “outdated” is much stronger than I thought.
15

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()))); 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.