Java stream collect 检查结果是否包含元素
Java stream collect check if result would contain element
因为我找不到与此相关的任何内容,我想知道流是否允许这样做。
在 my answer 另一个问题中,我有以下代码将元素添加到结果列表,前提是结果列表尚未包含它:
List<Entry<List<Integer>, Integer>> list = new ArrayList<>(diffMap.entrySet());
list.sort(Entry.comparingByValue());
List<List<Integer>> resultList = new ArrayList<>();
for (Entry<List<Integer>, Integer> entry2 : list) {
if (!checkResultContainsElement(resultList, entry2.getKey()))
resultList.add(entry2.getKey());
}
checkResultContainsElement
方法:
private static boolean checkResultContainsElement(List<List<Integer>> resultList, List<Integer> key) {
List<Integer> vals = resultList.stream().flatMap(e -> e.stream().map(e2 -> e2))
.collect(Collectors.toList());
return key.stream().map(e -> e).anyMatch(e -> vals.contains(e));
}
现在我想知道,如果这个 for 循环:
for (Entry<List<Integer>, Integer> entry2 : list) {
if (!checkResultContainsElement(resultList, entry2.getKey()))
resultList.add(entry2.getKey());
}
可以使用流来实现。我认为 .filter()
方法行不通,因为它会从 List<Entry<List<Integer>, Integer>> list
中删除数据,而我什至不知道是否应该考虑某个元素。我想自定义收集器可以工作,但我也不知道如何实现一个,因为结果会随着每个新添加的元素不断变化。
我正在寻找这样的东西(如果其他东西更好,可能会有所不同):
list.stream().sorted(Entry.comparingByValue()).collect(???);
其中 ???
将过滤数据并将其 return 作为列表。
一个结果列表的值可能不包含在另一个结果列表中。所以这些列表是有效的:
[1, 2, 3, 4]
[5, 6, 7, 8]
[12, 12, 12, 12]
但其中只有第一个有效:
[1, 2, 3, 4] <-- valid
[5, 3, 7, 8] <-- invalid: 3 already exists
[12, 12, 2, 12] <-- invalid: 2 already exists
可能是这样的:-
list.stream().
sorted(Entry.comparingByValue()).
collect(ArrayList<List<Foo>>::new,(x,y)->!checkResultContainsElement(x, y.getKey()),(x,y)->x.add(y.getKey()));
如果我们暂时搁置实施是否 stream-based 的细节,可以改进现有的如何检查传入列表值的唯一性的实施。
我们可以通过维护 Set
以前遇到的值来显着提高性能。
即添加到结果列表中的每个 list 中的 values 将存储在 set 中。为了确保每个传入的 list 的唯一性,将根据 set.
检查其值
由于流管道的操作应该是无状态的,收集器也不应该保持状态(即更改应该只在其可变容器内发生)。我们可以通过定义一个容器来解决这个问题,该容器将包含 Foo
列表的结果列表和一组 foo-values.
我已将此容器实现为 Java 16 条记录:
public record FooContainer(Set<Integer> fooValues, List<List<Foo>> foosList) {
public void tryAdd(List<Foo> foos) {
if (!hasValue(foos)) {
foos.forEach(foo -> fooValues.add(foo.getValue()));
foosList.add(foos);
}
}
public boolean hasValue(List<Foo> foos) {
return foos.stream().map(Foo::getValue).anyMatch(fooValues::contains);
}
}
上面显示的记录将用作使用 Colloctors.of()
创建的自定义收集器的可变容器。 Collector 的 accumulator
使用容器定义的 tryAdd()
方法。 finisher
从容器中提取 结果列表 。
注意 此操作不可并行化,因此收集器的 combiner
抛出 AssertionError
.
public static void main(String[] args) {
Map<List<Foo>, Integer> diffMap =
Map.of(List.of(new Foo(1), new Foo(2), new Foo(3)), 1,
List.of(new Foo(1), new Foo(4), new Foo(5)), 2,
List.of(new Foo(7), new Foo(8), new Foo(9)), 3);
List<List<Foo>> result = diffMap.entrySet().stream()
.sorted(Map.Entry.comparingByValue())
.map(Map.Entry::getKey)
.collect(Collector.of(
() -> new FooContainer(new HashSet<>(), new ArrayList<>()),
FooContainer::tryAdd,
(left, right) -> {throw new AssertionError("The operation isn't parallelizable");},
FooContainer::foosList
));
System.out.println(result);
}
输出:
[[Foo{1}, Foo{2}, Foo{3}], [Foo{7}, Foo{8}, Foo{9}]]
因为我找不到与此相关的任何内容,我想知道流是否允许这样做。
在 my answer 另一个问题中,我有以下代码将元素添加到结果列表,前提是结果列表尚未包含它:
List<Entry<List<Integer>, Integer>> list = new ArrayList<>(diffMap.entrySet());
list.sort(Entry.comparingByValue());
List<List<Integer>> resultList = new ArrayList<>();
for (Entry<List<Integer>, Integer> entry2 : list) {
if (!checkResultContainsElement(resultList, entry2.getKey()))
resultList.add(entry2.getKey());
}
checkResultContainsElement
方法:
private static boolean checkResultContainsElement(List<List<Integer>> resultList, List<Integer> key) {
List<Integer> vals = resultList.stream().flatMap(e -> e.stream().map(e2 -> e2))
.collect(Collectors.toList());
return key.stream().map(e -> e).anyMatch(e -> vals.contains(e));
}
现在我想知道,如果这个 for 循环:
for (Entry<List<Integer>, Integer> entry2 : list) {
if (!checkResultContainsElement(resultList, entry2.getKey()))
resultList.add(entry2.getKey());
}
可以使用流来实现。我认为 .filter()
方法行不通,因为它会从 List<Entry<List<Integer>, Integer>> list
中删除数据,而我什至不知道是否应该考虑某个元素。我想自定义收集器可以工作,但我也不知道如何实现一个,因为结果会随着每个新添加的元素不断变化。
我正在寻找这样的东西(如果其他东西更好,可能会有所不同):
list.stream().sorted(Entry.comparingByValue()).collect(???);
其中 ???
将过滤数据并将其 return 作为列表。
一个结果列表的值可能不包含在另一个结果列表中。所以这些列表是有效的:
[1, 2, 3, 4]
[5, 6, 7, 8]
[12, 12, 12, 12]
但其中只有第一个有效:
[1, 2, 3, 4] <-- valid
[5, 3, 7, 8] <-- invalid: 3 already exists
[12, 12, 2, 12] <-- invalid: 2 already exists
可能是这样的:-
list.stream().
sorted(Entry.comparingByValue()).
collect(ArrayList<List<Foo>>::new,(x,y)->!checkResultContainsElement(x, y.getKey()),(x,y)->x.add(y.getKey()));
如果我们暂时搁置实施是否 stream-based 的细节,可以改进现有的如何检查传入列表值的唯一性的实施。
我们可以通过维护 Set
以前遇到的值来显着提高性能。
即添加到结果列表中的每个 list 中的 values 将存储在 set 中。为了确保每个传入的 list 的唯一性,将根据 set.
检查其值由于流管道的操作应该是无状态的,收集器也不应该保持状态(即更改应该只在其可变容器内发生)。我们可以通过定义一个容器来解决这个问题,该容器将包含 Foo
列表的结果列表和一组 foo-values.
我已将此容器实现为 Java 16 条记录:
public record FooContainer(Set<Integer> fooValues, List<List<Foo>> foosList) {
public void tryAdd(List<Foo> foos) {
if (!hasValue(foos)) {
foos.forEach(foo -> fooValues.add(foo.getValue()));
foosList.add(foos);
}
}
public boolean hasValue(List<Foo> foos) {
return foos.stream().map(Foo::getValue).anyMatch(fooValues::contains);
}
}
上面显示的记录将用作使用 Colloctors.of()
创建的自定义收集器的可变容器。 Collector 的 accumulator
使用容器定义的 tryAdd()
方法。 finisher
从容器中提取 结果列表 。
注意 此操作不可并行化,因此收集器的 combiner
抛出 AssertionError
.
public static void main(String[] args) {
Map<List<Foo>, Integer> diffMap =
Map.of(List.of(new Foo(1), new Foo(2), new Foo(3)), 1,
List.of(new Foo(1), new Foo(4), new Foo(5)), 2,
List.of(new Foo(7), new Foo(8), new Foo(9)), 3);
List<List<Foo>> result = diffMap.entrySet().stream()
.sorted(Map.Entry.comparingByValue())
.map(Map.Entry::getKey)
.collect(Collector.of(
() -> new FooContainer(new HashSet<>(), new ArrayList<>()),
FooContainer::tryAdd,
(left, right) -> {throw new AssertionError("The operation isn't parallelizable");},
FooContainer::foosList
));
System.out.println(result);
}
输出:
[[Foo{1}, Foo{2}, Foo{3}], [Foo{7}, Foo{8}, Foo{9}]]