使用流从 Java 集合中提取

问题描述 投票:0回答:1

我想知道是否存在从基于给定

Collection
Predicate
实现中“提取”元素的实现,即在检索后删除所述元素。为了形象化我的意思,请考虑这个用例:

Set<Parent> parentSet = parentDao.getParents();
Set<Long> parentIdSet = parentSet.stream().map(Parent::getId).collect(Collectors.toSet())
Set<Child> childrenSet = childDao.getChildByParentIds(parentIdSet);

for (Parent parent : parentSet) {
   Set<Child> childrenOfThisParent = childrenSet
      .stream()
      .pluck((Child c) -> Objects.equals(parent.getId(), c.getParentId()))
      .collect(Collectors.toSet());

   parent.setChildren(childrenOfThisParent);
}

// At this line, childSet should be empty.
assert(childrenSet.isEmpty());

我想要的是每次迭代,在

Set<Child>
被它的
parentId
过滤并初始化为
childrenOfThisParent
之后,我希望它们从
childSet
中删除,并减少
size()
childSet
。实际上,从
childSet
开始的搜索在下一次迭代中应该会更快。尽管在这一点上,我必须进行基准测试才能知道更快的搜索时间是否会很重要。

java collections
1个回答
0
投票

流不支持“就地”操作,例如修改现有集合。如果您想对流执行此操作,则需要生成新的集合。您可以使用

partitioningBy
收集器将子集分为“此父级的子级”和“不是此父级的子级”。这两个都是新集合,存储在新的
Map
中。

for (Parent parent : parentSet) {
    var partitions =
        childrenSet.stream()
            .collect(Collectors.partitioningBy(
                c -> Objects.equals(parent.getId(), c.getParentId()),
                Collectors.toSet()
            ));
    childrenSet = partitions.get(false);

    parent.setChildren(partitions.get(true));
}

这会分配大量新集合,因此可能不值得。您可以考虑使用

groupingBy
:

在一个流中完成“将孩子分组到其父母”的整个操作
var childrenByParentId = childrenSet.stream().collect(Collectors.groupingBy(
    Child::getParentId,
    Collectors.toSet()
));
for (var parent: parentSet) {
    parent.setChildren(childrenByParentId.get(parent.getId()));
}
© www.soinside.com 2019 - 2024. All rights reserved.