multiple fields java-8 grouping java-stream collect

fields - Java 8 no mantiene el orden mientras se agrupa



stream collect grouping by (2)

Estoy usando Java 8 para agrupar por datos. Pero los resultados obtenidos no están en orden.

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; } }

Aquí estoy usando mi clase groupingKey por la cual estoy pasando dinámicamente desde ux. ¿Cómo puede obtener este groupByColumns en forma ordenada?


Basado en la gran respuesta de @ Holger. Publico esto para ayudar a aquellos que desean mantener el orden después de agrupar y cambiar el mapeo.

Simplifiquemos y supongamos que tenemos una lista de personas (int age, String name, String adresss ... etc) y queremos que los nombres se agrupen por edad manteniendo las edades en orden:

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, //keep the order Collectors.mapping(p -> p.getName(), //map name Collectors.toList())));


No mantener el orden es una propiedad del Map que almacena el resultado. Si necesita un comportamiento de Map específico, debe solicitar una implementación de Map particular . Por ejemplo, LinkedHashMap mantiene el orden de inserción:

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

Por cierto, no hay ninguna razón para copiar el contenido de mapList en una matriz antes de crear el Stream . Simplemente puede llamar a mapList.stream() para obtener una Stream adecuada.

Además, Collectors.mapping((Map<String, Object> p) -> p, toList()) está obsoleto. p->p es una asignación de identidad, por lo que no hay ninguna razón para solicitar la mapping en absoluto:

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

Pero incluso la GroupingKey es obsoleta. Básicamente, envuelve una List de valores, por lo que podría usar una List como clave en primer lugar. List hashCode implementan hashCode y son equals (pero no debe modificar estas hashCode clave después).

Map<List<Object>, List<Object>> groupedResult= mapList.stream().collect(Collectors.groupingBy( p -> groupByColumns.stream().map(p::get).collect(toList()), LinkedHashMap::new, toList()));