代码之家  ›  专栏  ›  技术社区  ›  Anonymous

如何分组到数组的映射中?

  •  1
  • Anonymous  · 技术社区  · 7 年前

    groupingBy 阵列 而不是列表或其他集合类型?

    例如:我有一节课 Thing . 东西都有主人,所以 事情 有一个 getOwnerId 方法在一个事物流中,我想按所有者ID对事物进行分组,以便具有相同所有者ID的事物最终在一个数组中组合在一起。换句话说,我想要一个如下所示的映射,其中键是所有者ID,值是属于该所有者的事物的数组。

        Map<String, Thing[]> mapOfArrays;
    

    Map<String, Thing[]> .

    将整个流收集到一个数组很容易(它甚至不需要显式收集器):

        Thing[] arrayOfThings = Stream.of(new Thing("owner1"), new Thing("owner2"), new Thing("owner1"))
                .toArray(Thing[]::new);
    

    [属于所有者1,属于所有者2,属于所有者1]

    通过所有者ID进行摸索也很容易。例如,要分组到列表中:

        Map<String, List<Thing>> mapOfLists = Stream.of(new Thing("owner1"), new Thing("owner2"), new Thing("owner1"))
                .collect(Collectors.groupingBy(Thing::getOwnerId));
    

    只有这个例子给了我一张地图 列表 . 有2-arg和3-arg 分组依据 方法,这些方法可以为我提供其他集合类型(如集合)的映射。我想,如果我可以将一个收集到数组中的收集器(类似于上面第一个代码段中收集到数组中的收集器)传递给两个参数 Collectors.groupingBy​(Function<? super T,? extends K>, Collector<? super T,A,D>) ,无法设置Id。但是,中没有预定义的收集器 Collectors 类似乎可以处理数组。我错过了一条不太复杂的路吗?

    为了提供完整的示例,以下是我在上述代码片段中使用的类:

    public class Thing {
    
        private String ownerId;
    
        public Thing(String ownerId) {
            this.ownerId = ownerId;
        }
    
        public String getOwnerId() {
            return ownerId;
        }
    
        @Override
        public String toString() {
            return "Belongs to " + ownerId;
        }
    
    }
    
    3 回复  |  直到 7 年前
        1
  •  4
  •   Anonymous    7 年前

    从中使用收集器 this answer by Thomas Pliakas :

        Map<String, Thing[]> mapOfArrays = Stream.of(new Thing("owner1"), new Thing("owner2"), new Thing("owner1"))
                .collect(Collectors.groupingBy(Thing::getOwnerId,
                        Collectors.collectingAndThen(Collectors.toList(),
                                tl -> tl.toArray(new Thing[0]))));
    

    其思想是首先收集到一个列表中(这是一个明显的想法,因为数组的大小是恒定的),然后在返回到 按分组 collectingAndThen 可以通过它所谓的终结者做到这一点。

        mapOfArrays.forEach((k, v) -> System.out.println(k + '=' + Arrays.toString(v)));
    
    owner1=[Belongs to owner1, Belongs to owner1]
    owner2=[Belongs to owner2]
    

    编辑: 感谢Aomine提供的链接:使用 new Thing[0] 作为论据 toArray 灵感来自 Arrays of Wisdom of the Ancients . 看来在英特尔CPU上到底用的是什么 比使用更快捷 new Thing[tl.size()] . 我很惊讶。

        2
  •  2
  •   Ousmane D.    7 年前

    您可以先分组,然后使用后续的toMap:

    Map<String, Thing[]> result = source.stream()
                    .collect(groupingBy(Thing::getOwnerId))
                    .entrySet()
                    .stream()
                    .collect(toMap(Map.Entry::getKey,
                            e -> e.getValue().toArray(new Thing[0])));
    
        3
  •  2
  •   Eugene    7 年前

    可能很明显,但您可以通过以下方式完成:

    Stream.of(new Thing("owner1"), new Thing("owner2"), new Thing("owner1"))
                .collect(Collectors.toMap(
                        Thing::getOwnerId,
                        x -> new Thing[]{x},
                        (left, right) -> {
                            Thing[] newA = new Thing[left.length + right.length];
                            System.arraycopy(left, 0, newA, 0, left.length);
                            System.arraycopy(right, 0, newA, left.length, right.length);
                            return newA;
                        }
                ))