我需要删除ArrayList
中的某些对象,如果它们符合条件并且我想知道哪种方式可以更有效。
情况就是这样:我有一个包含ArrayList
的类,其中包含一些其他对象。我必须遍历此ArrayList
并删除满足特定条件的所有元素。
据我所知,这些将是我删除的选项:
创建新的ArrayList
并添加不符合条件的元素。在迭代之后,从旧的arraylist交换到没有元素的新arraylist。
创建一个新的ArrayList
并添加符合条件的元素。在迭代之后,使用removeAll()
方法将ArrayList
与要删除的对象一起传递。
是否有更有效的方法从ArrayList
删除对象?
答案 0 :(得分:47)
您可以向后迭代并在浏览ArrayList时删除。这样做的好处是后续元素不需要移动,并且比向前移动更容易编程。
答案 1 :(得分:16)
另一种方式:Iterator有一个可选的remove()方法,它是为ArrayList实现的。您可以在迭代时使用它。
我不知道,哪种变体是最高效的,你应该测量它。
starblue评论说,复杂性并不好,而且这也是真的(对于removeAll()),因为ArrayList必须复制所有元素,如果在中间是添加或删除的元素。对于那种情况,LinkedList应该更好。但是,由于我们都不知道您的真实用例,所以最好的方法是测量所有变体,以选择最佳解决方案。答案 2 :(得分:12)
我认为,大多数高性能用户都会使用listIterator
方法进行反向迭代:
for (ListIterator<E> iter = list.listIterator(list.size()); iter.hasPrevious();){
if (weWantToDelete(iter.previous())) iter.remove();
}
编辑:很久以后,人们可能还想使用lambda或方法引用从列表(或任何集合!)中添加the Java 8 way of removing elements。如果您愿意,可以使用集合的filter
:
list.removeIf(e -> e.isBad() && e.shouldGoAway());
这可能是清理集合的最佳方法。由于它使用内部迭代,因此集合实现可以采用快捷方式使其尽可能快(对于ArrayList
s,它可以最小化所需的复制量。)
答案 3 :(得分:5)
显然,在你提到的两种方法中,数字1更有效率,因为它只需要遍历列表一次,而使用方法编号2,列表必须遍历两次(首先找到要删除的元素,并将它们移除。)
实际上,从另一个列表中删除元素列表可能是一种比O(n)更差的算法,所以方法2更糟糕。
迭代器方法:
List data = ...;
for (Iterator i = data.iterator(); i.hasNext(); ) {
Object element = i.next();
if (!(...)) {
i.remove();
}
}
答案 4 :(得分:4)
首先,我确保这确实是一个性能瓶颈,否则我会选择最干净,最具表现力的解决方案。
如果它是性能瓶颈,只需尝试不同的策略,看看哪个是最快的。我敢打赌创建一个新的ArrayList并将所需的对象放在那个中,丢弃旧的ArrayList。
答案 5 :(得分:1)
除非你肯定你所面临的问题确实是一个瓶颈,否则我会去寻找可读的
public ArrayList filterThings() {
ArrayList pileOfThings;
ArrayList filteredPileOfThings = new ArrayList();
for (Thing thingy : pileOfThings) {
if (thingy.property != 1) {
filteredPileOfThings.add(thingy);
}
}
return filteredPileOfThings;
}
答案 6 :(得分:1)
从ArrayList中删除元素有隐藏的成本。每次删除元素时,都需要移动元素以填充“洞”。平均而言,这将为包含N个元素的列表进行N / 2
分配。
因此,从N元素ArrayList中删除M个元素的平均值为O(M * N)
。 O(N)解决方案涉及创建新列表。例如。
List data = ...;
List newData = new ArrayList(data.size());
for (Iterator i = data.iterator(); i.hasNext(); ) {
Object element = i.next();
if ((...)) {
newData.add(element);
}
}
如果N很大,我的猜测是,对于M小到3或4的值,这种方法会比remove
方法快。
但重要的是要创建足够大的newList
以容纳list
中的所有元素,以避免在展开后复制后备数组。
答案 7 :(得分:1)
int sizepuede= listaoptionVO.size();
for (int i = 0; i < sizepuede; i++) {
if(listaoptionVO.get(i).getDescripcionRuc()==null){
listaoptionVO.remove(listaoptionVO.get(i));
i--;
sizepuede--;
}
}
编辑:添加缩进
答案 8 :(得分:0)
答案 9 :(得分:0)
我找到了另一种更快的解决方案:
int j = 0;
for (Iterator i = list.listIterator(); i.hasNext(); ) {
j++;
if (campo.getNome().equals(key)) {
i.remove();
i = list.listIterator(j);
}
}
答案 10 :(得分:0)
使用迭代器,您可以始终处理按顺序排列的元素,而不是指定的索引。所以,你不应该对上述问题感到困扰。
Iterator itr = list.iterator();
String strElement = "";
while(itr.hasNext()){
strElement = (String)itr.next();
if(strElement.equals("2"))
{
itr.remove();
}
答案 11 :(得分:0)
虽然这是违反直觉的,但这是我大量加快这项操作的方式。
正是我在做什么:
ArrayList < HashMap < String , String >> results; // This has been filled with a whole bunch of results
ArrayList&lt; HashMap&lt;字符串,字符串&gt; &GT; discard = findResultsToDiscard(results);
results.removeall(丢弃);
然而,删除所有方法花费了超过6秒(不包括获取丢弃结果的方法)从2000(ish)数组中删除大约800个结果。
我尝试了gustafc和其他人在这篇文章中提出的迭代器方法。
这确实加快了操作速度(降至约4秒),但这仍然不够好。所以我尝试了一些有风险的事情......
ArrayList < HashMap < String, String>> results;
List < Integer > noIndex = getTheDiscardedIndexs(results);
for (int j = noIndex.size()-1; j >= 0; j-- ){
results.remove(noIndex.get(j).intValue());
}
虽然getTheDiscardedIndexs保存了一个索引数组,而不是一个HashMaps数组。事实证明,加速删除对象的速度要快得多(现在大约0.1秒)并且内存效率会更高,因为我们不需要创建大量的结果来删除。
希望这有助于某人。
答案 12 :(得分:-2)
我很擅长Mnementh的推荐。
只是一个警告,
ConcurrentModificationException
请注意,您没有运行多个线程。如果执行多个线程,并且线程未完全同步,则可能出现此异常。