PartitionBy产生了意外的结果

0wi1tuuw  于 2021-07-12  发布在  Java
关注(0)|答案(2)|浏览(367)

我有一个测试程序:

public class App {

    public static void main(String[] args) {

        List<Integer> a = Arrays.asList(1, 11);
        List<Integer> b = Arrays.asList(2, 22);
        List<Integer> c = Arrays.asList(3, 33);

        Map<String, List<Integer>> map = new HashMap<>();
        map.put("a", a);
        map.put("b", b);
        map.put("c", c);

        Set<String> valid = new HashSet<>();
        valid.add("a");

        Map<Boolean, List<Map.Entry<String, List<Integer>>>> partitions =
            map.entrySet().stream()
                .collect(Collectors.partitioningBy(
                    entry -> valid.contains(entry.getKey())));

        System.out.println(partitions);

        // partition by the key of the map
        // then reduce the values into a single collection

        Map<Boolean, List<Integer>> result = map.entrySet().stream()
            .collect(Collectors.partitioningBy(
                entry -> valid.contains(entry.getKey()),
                Collectors.mapping(Map.Entry::getValue,
                                   Collectors.reducing(new ArrayList<>(),
                                                       (l1, l2) -> {
                                                           l1.addAll(l2);
                                                           return l1;
                                                       }))));

        System.out.println(result);
    }
}

我期待最后的结果是

{false=[b=[2, 22], c=[3, 33]], true=[a=[1, 11]]}
{false=[2, 22, 3, 33], true=[1, 11]}

但在实际结果中,真、假键都有6个整数:

{false=[b=[2, 22], c=[3, 33]], true=[a=[1, 11]]}
{false=[1, 11, 2, 22, 3, 33], true=[1, 11, 2, 22, 3, 33]}

注意这两个分区函数是完全相同的。但是下游将不同分区中的值混合在一起。怎么会这样?我假设下游只在每个分区上运行。。。
我错过了什么?
谢谢。

tjvv9vkg

tjvv9vkg1#

为了减少数据量,在两个分区中使用相同的arraylist引用。你可以用 Collectors.toMap 并创建一个合并两个列表的新示例。

Map<Boolean, List<Integer>> result = 
        map.entrySet()
        .stream()
        .collect(Collectors.toMap(e -> valid.contains(e.getKey()), Map.Entry::getValue, 
        (l1, l2) -> {
          List<Integer> l3 = new ArrayList<>(l1);
          l3.addAll(l2);
          return l3;
        }));

如果你想用同样的味道

Map<Boolean, List<Integer>> result = 
        map.entrySet()
        .stream()
        .collect(Collectors.toMap(e-> valid.contains(e.getKey()), Map.Entry::getValue,
            (l1, l2) -> Stream.concat(l1.stream(), l2.stream())
                              .collect(Collectors.toList())));
6l7fqoea

6l7fqoea2#

要完成已接受的答案,您可以使用 Collectors.groupingBy 使用分类器 Collectors.flatMapping 作为下游收集器的Java9。

Map<Boolean, List<Integer>> result = map.entrySet().stream()
    .collect(Collectors.groupingBy(
         e -> valid.contains(e.getKey()), 
         Collectors.flatMapping(e -> e.getValue().stream(), Collectors.toList())));

相关问题