web-dev-qa-db-ja.com

Java 8はグループ化中に順序を維持していません

データによるグループ化にはJava 8を使用します。ただし、得られた結果は順序どおりではありません。

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

    }

ここで私は私のクラスgroupingKeyを使用しています。これにより、uxから動的に渡されます。このgroupByColumnsをソートされた形式で取得するにはどうすればよいですか?

26
Shreya Shah

順序を維持しないのは、結果を格納するMapのプロパティです。特定のMap動作が必要な場合は、 特定のMap実装を要求 する必要があります。例えば。 LinkedHashMap は挿入順序を維持します:

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

ちなみに、mapListを作成する前に、Streamの内容を配列にコピーする必要はありません。 mapList.stream()を呼び出すだけで、適切なStreamを取得できます。

さらに、Collectors.mapping((Map<String, Object> p) -> p, toList())は廃止されました。 _p->p_はIDマッピングであるため、mappingを要求する理由はまったくありません。

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

しかし、GroupingKeyでさえ時代遅れです。基本的にListの値をラップするので、そもそもListをキーとして使用するだけで済みます。 ListsはhashCodeおよびequalsを適切に実装します(ただし、してはいけませんこれらのキーを変更してくださいListsその後)。

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

@Holgerの素晴らしい答えに基づいています。これを投稿して、グループ化やマッピングの変更後も順序を維持したい人を支援します。

単純化して、人のリスト(int age、String name、String adresssなど)があり、年齢を順番に保ちながら年齢別にグループ化したいとします。

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