英文:
partitioningBy with a downstream collector produced an unexpected result
问题
我有一个测试程序:
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);
// 根据映射的键进行分区
// 然后将值减少为单个集合
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]}
但实际结果中,true 和 false 键都有全部 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]}
注意两个分区函数完全相同。但下游混淆了单独分区中的值。这怎么可能?我认为下游只会对每个分区进行操作…
我在这里漏掉了什么?
谢谢。
英文:
I have a test program:
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);
}
}
I'm expecting the final result to be
{false=[b=[2, 22], c=[3, 33]], true=[a=[1, 11]]}
{false=[2, 22, 3, 33], true=[1, 11]}
But in the actual result, both true and false keys have all 6 integers:
{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]}
Notice the 2 partitioning functions are exactly the same. But the downstream mixed up the values in the separate partitions. How can that be? I assume the downstream would only operate on each partition...
What did I miss here?
Thanks.
答案1
得分: 1
为了减少相同的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())));
英文:
For reducing same ArrayList reference is used in both partition.
You can use Collectors.toMap
and create a new instance merging two lists.
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;
}));
And if you want to use the same taste
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())));
答案2
得分: 0
为了完成已经接受的答案,你可以在Java 9中使用Collectors.groupingBy
,并结合使用分类器和Collectors.flatMapping
作为下游收集器。
Map<Boolean, List<Integer>> result = map.entrySet().stream()
.collect(Collectors.groupingBy(
e -> valid.contains(e.getKey()),
Collectors.flatMapping(e -> e.getValue().stream(), Collectors.toList())));
英文:
To complete already accepted answer, you can use Collectors.groupingBy
using your classifier with Collectors.flatMapping
as of Java 9 as a downstream collector.
Map<Boolean, List<Integer>> result = map.entrySet().stream()
.collect(Collectors.groupingBy(
e -> valid.contains(e.getKey()),
Collectors.flatMapping(e -> e.getValue().stream(), Collectors.toList())));
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论