繁体   English   中英

如何根据谓词有效地将对象从一个java集合转移到另一个集合?

[英]How can I efficiently transfer objects from one java collection to an other according to a predicate?

首先,我希望以前没有问过这个问题。 我看了一下,找不到合适的答案:s

当特定条件成立时,我正在寻找一种将一些对象从一个集合移动到另一个集合的有效方法。

目前,我会以非常简单的方式做到这一点,但我担心这可能不是最佳的:

Collection<Object> myFirstCollection;  //let's consider it instanciated and populated
Collection<Object> mySecondCollection; //same for this one

myFirstCollection.stream().forEach(o -> { 
    if ( conditionReturningTrue(o) ) {
        mySecondCollection.add(o);
        myFirstCollection.remove(o);
    }
});

你知道更好的方式/更有效率吗?

为了使其更具可读性,在这种情况下使用Collection::addAllCollection::removeAll ,您的代码可以是:

// create a new Collection where you use filter to search only the Object you want
Collection<Object> filterdCollection = myFirstCollection.stream()
        .filter(o -> conditionReturningTrue(o))
        .collect(Collectors.toCollection(LinkedHashSet::new));

// use allAll to add all the filtered Object to the second collection
mySecondCollection.addAll(filterdCollection);
// use removeAll to remove all the filtered Object from the first collection
myFirstCollection.removeAll(filterdCollection);

首先,你应该努力争取正确性。 对于大多数集合,禁止在迭代时修改源集合。 尝试时可能会遇到ConcurrentModificationException ,但即使它碰巧没有异常运行,代码仍然不正确。 只是这个错误并不总是被检测到(这是一次尽力而为的检查,试图避免浪费太多的性能)。 这适用于forEach(…) ,以及stream().forEach(…)和for-each循环( for(variable declaration: collection)

迭代时删除元素的唯一支持是通过手动Iterator使用:

for(Iterator<Object> it = myFirstCollection.iterator(); it.hasNext(); ) {
    Object o = it.next();
    if(conditionReturningTrue(o)) {
        it.remove();
        mySecondCollection.add(o);
    }
}

替代方法是批量方法。

首先,像显示在这个那个答案,创建所有元素的副本将被首先转移。

其次,你可以使用

myFirstCollection.removeIf(o -> conditionReturningTrue(o) && mySecondCollection.add(o));

removeIfdefault实现在类似于上面的循环中使用Iterator 但是,像ArrayList这样的集合提供了自己的removeIf实现,以克服Iterator循环的二次时间复杂度。

您可以通过使用Collectors.partitioningBy将原始Collection拆分为两个List来避免removeAll (可能需要对象查找需要线性搜索的某些Collection的二次时间,例如List )来提高性能:

Collection<Object> myFirstCollection;  //let's consider it instanciated and populated
Collection<Object> mySecondCollection; //same for this one

Map<Boolean,List<Object>> partition = 
    myFirstCollection.stream()
                     .collect(Collectors.partitioningBy(o -> conditionReturningTrue(o)));
myFirstCollection.clear();
myFirstCollections.addAll(partition.get(false));
mySecondCollection.addAll(partition.get(true));

另一方面,如果只有少数元素应该从myFirstCollection移动到myFirstCollection ,那么这个解决方案可能效率mySecondCollection

您已经从YCF_L得到了一个很好的答案: https ://stackoverflow.com/a/52295144/9568238

但是我想补充一点,如果你按照你在问题中描述的那样去做forEach方法,那么stream()是多余的。 你可以做myFirstCollection.forEach(...)

无论哪种方式,我都会回答上面提到的答案。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM