Java 8流唯一整数

uinbv5nw  于 2023-01-11  发布在  Java
关注(0)|答案(5)|浏览(114)

我可以把下面的代码减少到一行或两行吗?

DTO dto;
List<DTO> dtos;
List<Integer> list1 = dtos.stream().map(DTO::getFirstId).distinct().collect(Collectors.toList());
List<Integer> list2 = dtos.stream().map(DTO::getSecondId).distinct().collect(Collectors.toList());

List<Integer> reducedId = list1.stream().filter(list2::contains).collect(Collectors.toList());
sq1bmfud

sq1bmfud1#

使用单个Java8流在这里不是一个好的选择,相反,您应该首先创建一个Set,以便可以执行有效的包含测试。

Set<Integer> secondIds = dtos.stream().map(DTO::getSecondId).collect(Collectors.toSet());
List<Integer> reducedIds = dtos.stream().map(DTO::getFirstId).distinct()
        .filter(secondIds::contains).collect(Collectors.toList());
li9yvcax

li9yvcax2#

您可以强制将其合并到一个流操作中,但是性能会比您现在所拥有的(即具有二次时间复杂度的操作)还要差。
更好的方法是:

Set<Integer> set = dtos.stream().map(DTO::getSecondId).collect(Collectors.toSet());
List<Integer> result = dtos.stream().map(DTO::getFirstId)
    .distinct().filter(set::contains).collect(Collectors.toList());
// result now contains the common IDs

通过将第二个ID收集到Set而不是List中,您无需在第一个流操作中使用distinct(),并且避免了在调用contains时对第二个流操作中的每个元素应用线性搜索。
一般可以考虑使用Set来记忆唯一ID,当使用Set作为结果类型时,也可以避免第二个流操作的distinct()

Set<Integer> set = dtos.stream().map(DTO::getSecondId).collect(Collectors.toSet());
Set<Integer> result = dtos.stream().map(DTO::getFirstId)
    .filter(set::contains).collect(Collectors.toSet());

如果您怀疑存在大量重复的ID,并希望在检查其他Set之前保留对重复项进行排序的行为,则可以用途:

Set<Integer> set = dtos.stream().map(DTO::getSecondId).collect(Collectors.toSet());
Set<Integer> result = dtos.stream().map(DTO::getFirstId)
    .collect(Collectors.toCollection(HashSet::new));
result.retainAll(set);

请注意,如果您喜欢又长又难读的“一行程序”,则可以在所有变体中内联set变量。

djmepvbi

djmepvbi3#

如果你愿意使用第三方库,你可以选择使用Eclipse Collections。如果你想使用Stream,下面的代码应该可以使用Collectors2

MutableList<Integer> result =
    dtos.stream().map(DTO::getFirstId).collect(Collectors2.toSet())
        .intersect(dtos.stream().map(DTO::getSecondId).collect(Collectors2.toSet()))
        .toList();

Eclipse集合也有它唯一的LazyIterable类型可以用来代替Stream

LazyIterable<DTO> iterable = LazyIterate.adapt(dtos);
MutableList<Integer> result =
    iterable.collect(DTO::getFirstId).toSet()
        .intersect(iterable.collect(DTO::getSecondId).toSet())
        .toList();

最后,如果你有大量的id,你可能想使用原语集来避免装箱Integer对象。你可以再次使用StreamCollectors2,如下所示:

IntSet second = dtos.stream().collect(
    Collectors2.collectInt(DTO::getSecondId, IntSets.mutable::empty));
IntList result = dtos.stream().collect(
    Collectors2.collectInt(DTO::getFirstId, IntSets.mutable::empty))
        .select(second::contains).toList();

也可以按如下方式使用LazyIterable

LazyIterable<DTO> iterable = LazyIterate.adapt(dtos);
IntList result =
    iterable.collectInt(DTO::getFirstId).toSet()
        .select(iterable.collectInt(DTO::getSecondId).toSet()::contains)
        .toList();

注意:我是Eclipse Collections的提交者。

b5buobof

b5buobof4#

使用StreamEx时:

Set<Integer> set = StreamEx.of(dtos).map(DTO::getSecondId).toSet();
List<Integer> result = StreamEx.of(dtos).map(DTO::getFirstId)
                                        .filter(set::contains).distinct().toList();

或通过abacus-common

Set<Integer> set = Stream.of(dtos).map(DTO::getSecondId).toSet();
List<Integer> result = Stream.of(dtos).map(DTO::getFirstId)
                                        .filter(set::contains).distinct().toList();

// OR:

List<Integer> result = Stream.of(dtos).map(DTO::getFirstId)
       .intersection(Stream.of(dtos).map(DTO::getSecondId).toSet()).toList();
eoxn13cs

eoxn13cs5#

我觉得你可以做一些

List<Integer> reducedId = dtos.stream().map(DTO::getFirstId).distinct().filter(
    (dtos.stream().map(DTO::getSecondId).distinct().collect(Collectors.toList()))::contains
).collect(Collectors.toList());

没有在我当地测试,但在我看来是合理的:)

相关问题