Java 8在分组时不维护顺序

Shr*_*hah 22 grouping collect java-8 java-stream

我使用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;
        }

    }
Run Code Online (Sandbox Code Playgroud)

在这里我使用我的类groupingKey,我通过它动态地从ux传递.如何以排序的形式获取此groupByColumns?

Hol*_*ger 49

不维护订单是Map存储结果的属性.如果您需要特定的Map行为,则需要请求特定的Map实现.例如,LinkedHashMap维护插入顺序:

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

顺便说一下,没有理由mapList在创建之前将内容复制到数组中Stream.你可以简单地打电话mapList.stream()来获得合适的Stream.

此外,Collectors.mapping((Map<String, Object> p) -> p, toList())已经过时了.p->p是一个身份映射,所以没有理由要求mapping:

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

但即使GroupingKey是过时的.它基本上包含了List一些值,因此您可以首先使用Listas键.List实施hashCodeequals适当(但你不能List在之后修改这些密钥).

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

  • @geneb。`Collectors.toList()`。在组合收集器时,您可以使用“import static java.util.stream.Collectors.*;”来避免重复使用“Collectors.”。 (2认同)

hzi*_*oun 11

基于@Holger 的精彩回答。我发布此信息是为了帮助那些希望在分组和更改映射后保持顺序的人。

让我们简化一下,假设我们有一个人员列表(整数年龄、字符串名称、字符串地址...等),并且我们希望名称按年龄分组,同时保持年龄顺序:

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())));
Run Code Online (Sandbox Code Playgroud)