2011-06-08 61 views
5

我需要过滤一个ArrayList并删除找到的元素。对于Java相对较新,我想知道最有效的方法是实现这个目标(因为它在移动设备上运行)。目前我这样做:Java:高效的ArrayList过滤?

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

它可以做到没有临时对象?也许通过直接操作(删除)迭代列表中的元素?

+1

还有其他数据结构的项目删除更有效。从LinkedList中删除将具有O(n)性能。从HashMap中删除将具有恒定的时间性能。 – 2011-06-08 15:40:33

回答

16

有效地除去了一些从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支持lambdas时,我们可以期望有重大的改进,并且增强了收集API以使用它们。

+0

谢谢Stephen,为您提供极好的深入解释!所以回家的信息是填充一个新的ArrayList通常比从现有的元素中移除元素更好。很高兴知道! – Bachi 2011-06-12 00:04:44

7

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

+1

(如果迭代器提供了删除的实现 - 它可能会抛出一个UnsupportedOperationException异常 - 所以这只适用于你非常了解你的迭代器的情况) – 2011-06-08 14:58:10

4

的一种方法将使用迭代器,而不是为每个:

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