Java:高效的 ArrayList 过滤?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/6280722/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Java: Efficient ArrayList filtering?
提问by Bachi
I need to filter an ArrayList and remove found elements. Being relatively new to Java, I'm wondering what the most efficent method is to achieve this (matters because it runs on mobile devices). Currently I do this:
我需要过滤一个 ArrayList 并删除找到的元素。作为 Java 的新手,我想知道实现这一目标的最有效方法是什么(很重要,因为它在移动设备上运行)。目前我这样做:
// We display only top-level dealers (parentId=-10)
ArrayList<DealerProductCount> subDealers = new ArrayList<DealerProductCount>();
for (DealerProductCount dealer : wsResponse.Dealers) {
if (dealer.ParentId != -10) subDealers.add(dealer);
}
wsResponse.Dealers.removeAll(subDealers);
Can it be done without temporary objects? Maybe by directly manipulating (removing) elements of the list being iterated?
可以在没有临时对象的情况下完成吗?也许通过直接操作(删除)正在迭代的列表的元素?
回答by Stephen C
Efficiently removing a number of elements from an ArrayList
requires some thought. The naive approach is something like this:
有效地从一个元素中删除一些元素ArrayList
需要一些思考。天真的方法是这样的:
Iterator<DealerProductCount> it = wsResponse.Dealers.iterator();
while (it.hasNext()) {
if (it.next().ParentId != -10) {
it.remove();
}
}
The problem is that each time you remove an element you copy (on average) half of the remaining elements. This is because removing an element from an ArrayList
entails copying all elements after element removed one position to the left.
问题在于,每次删除一个元素时,您都会复制(平均)剩余元素的一半。这是因为从 a 中删除元素ArrayList
需要在元素向左删除一个位置后复制所有元素。
Your original solution involving the list of elements to be removed essentially does the same thing. Unfortunately, the properties of an ArrayList
don't allow removeAll
to do better than the above.
您的原始解决方案涉及要删除的元素列表,基本上做同样的事情。不幸的是, a 的属性ArrayList
不允许removeAll
做得比上面更好。
If you expect to remove a number of elements, the following is more efficient:
如果您希望删除多个元素,以下方法更有效:
ArrayList<DealerProductCount> retain =
new ArrayList<DealerProductCount>(wsResponse.Dealers.size());
for (DealerProductCount dealer : wsResponse.Dealers) {
if (dealer.ParentId == -10) {
retain.add(dealer);
}
}
// either assign 'retain' to 'wsResponse.Dealers' or ...
wsResponse.Dealers.clear();
wsResponse.Dealers.addAll(retain);
We are copying (almost) the entire list twice, so this should break even (on average) if you remove as few as 4 elements.
我们复制(几乎)整个列表两次,所以如果你删除少至 4 个元素,这应该(平均)收支平衡。
It is interesting to note that functional programming languages / libraries typical support a filter method, and that can do this task in one pass through the list; i.e. a lot more efficiently. I think we can expect significant improvements if / when Java supports lambdas, and the collection APIs are enhanced to use them.
有趣的是,函数式编程语言/库通常支持过滤器方法,并且可以通过列表一次完成此任务;即更有效。我认为如果/当 Java 支持 lambda 并且集合 API 得到增强以使用它们时,我们可以期待重大改进。
UPDATEand with Java 8 lambdas and streams, we get them ... for this use-case.
UPDATE和 Java 8 lambdas 和流,我们得到它们......对于这个用例。
回答by Petar Minchev
If you use an iterator you can remove safely elements while iterating.
如果您使用迭代器,您可以在迭代时安全地删除元素。
回答by Joshua
One way would use the iterator instead of the for each:
一种方法是使用迭代器而不是 for each:
Iterator<DealerProductCount> iter = wsResponse.Dealers.iterator()
while(iter.hasNext()) {
if (iter.next().ParentId != -10) iter.remove();
}