web-dev-qa-db-fra.com

Java 8 ne maintient pas l'ordre lors du regroupement

J'utilise Java 8 pour le regroupement par données. Mais les résultats obtenus ne sont pas classés dans l'ordre.

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

    }

Ici, j'utilise ma classe groupingKey par laquelle je passe dynamiquement de ux. Comment obtenir ce groupByColumns sous forme triée?

26
Shreya Shah

Le non-maintien de l'ordre est une propriété du Map qui stocke le résultat. Si vous avez besoin d'un comportement Map spécifique, vous devez demander une implémentation Map particulière . Par exemple. LinkedHashMap maintient l'ordre d'insertion:

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

Soit dit en passant, il n'y a aucune raison de copier le contenu de mapList dans un tableau avant de créer le Stream. Vous pouvez simplement appeler mapList.stream() pour obtenir un Stream approprié.

De plus, Collectors.mapping((Map<String, Object> p) -> p, toList()) est obsolète. p->p Est un mappage d'identité, il n'y a donc aucune raison de demander mapping:

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

Mais même le GroupingKey est obsolète. Il enveloppe essentiellement un List de valeurs, vous pouvez donc simplement utiliser un List comme clé en premier lieu. Lists implémentent hashCode et equals de manière appropriée (mais vous ne devez pas modifier ces clés Lists après).

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

Basé sur la grande réponse de @ Holger. Je poste ceci pour aider ceux qui veulent conserver l'ordre après le regroupement ainsi que la modification du mappage.

Simplifions et supposons que nous ayons une liste de personnes (int age, nom de chaîne, adresses de chaîne ... etc) et nous voulons que les noms soient groupés par âge tout en gardant les âges dans l'ordre:

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