从Java中删除ArrayList中的对象

时间:2009-08-21 07:41:03

标签: java performance memory-management arraylist

我需要删除ArrayList中的某些对象,如果它们符合条件并且我想知道哪种方式可以更有效。

情况就是这样:我有一个包含ArrayList的类,其中包含一些其他对象。我必须遍历此ArrayList并删除满足特定条件的所有元素。 据我所知,这些将是我删除的选项:

  1. 创建新的ArrayList并添加不符合条件的元素。在迭代之后,从旧的arraylist交换到没有元素的新arraylist。

  2. 创建一个新的ArrayList并添加符合条件的元素。在迭代之后,使用removeAll()方法将ArrayList与要删除的对象一起传递。

  3. 是否有更有效的方法从ArrayList删除对象?

13 个答案:

答案 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)

也许是Iteratorremove()方法? JDK的默认集合类应该是支持此方法的所有创建者迭代器。

答案 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

请注意,您没有运行多个线程。如果执行多个线程,并且线程未完全同步,则可能出现此异常。