Java:高效的ArrayList过滤?

时间:2011-06-08 14:49:47

标签: java android arraylist

我需要过滤一个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);

可以在没有临时对象的情况下完成吗?也许通过直接操作(删除)正在迭代的列表元素?

3 个答案:

答案 0 :(得分:19)

ArrayList有效地删除大量元素需要一些思考。天真的方法是这样的:

Iterator<DealerProductCount> it = wsResponse.Dealers.iterator();
while (it.hasNext()) {
    if (it.next().ParentId != -10) { 
        it.remove(); 
    }
}

问题在于每次删除元素时(平均)复制剩余元素的一半。这是因为从ArrayList中删除元素需要在元素向左移除一个位置后复制所有元素。

涉及要删除的元素列表的原始解决方案基本上做同样的事情。不幸的是,ArrayList的属性不允许removeAll做得比上面做得更好。

如果您希望删除多个元素,以下内容会更有效:

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);

我们正在复制(几乎)整个列表两次,所以如果你只删除4个元素,这应该是平均的。


值得注意的是,函数式编程语言/库通常支持过滤方法,并且可以通过列表一次完成此任务;即更有效率。我认为如果/当Java支持lambda时我们可以期待显着的改进,并且集合API被增强以使用它们。

UPDATE 以及Java 8 lambdas和流,我们得到它们......对于这个用例。

答案 1 :(得分:7)

如果使用迭代器,则可以在迭代时安全地删除元素。

答案 2 :(得分:4)

一种方法是使用迭代器而不是每个:

Iterator<DealerProductCount> iter = wsResponse.Dealers.iterator()
while(iter.hasNext()) {
    if (iter.next().ParentId != -10) iter.remove();
}