在 Java 中从 ArrayList 中删除对象

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1310532/
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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-12 08:05:21  来源:igfitidea点击:

Deleting objects from an ArrayList in Java

javaperformancememory-managementarraylist

提问by Carlos Pastor

I need to delete some objects from an ArrayListif they meet a condition and I'm wondering which way could be more efficient.

ArrayList如果它们满足条件,我需要从它们中删除一些对象,我想知道哪种方式可能更有效。

Here's the situation: I have a class that contains an ArrayListcontaining some other objects. I have to iterate over this ArrayListand delete all elements meeting a certain condition. As far as I know, those would be my options to delete:

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

  1. Create a new ArrayListand add the elements that doesn't meet the condition. After the iteration, swap from the old arraylist to the new one without the elements.

  2. Create a new ArrayListand add the elements that meet the condition. After the iteration, use the removeAll()method passing the ArrayListwith the objects to be deleted.

  1. 创建一个新的ArrayList并添加不满足条件的元素。迭代后,从旧的arraylist 交换到没有元素的新arraylist。

  2. 创建一个新的ArrayList并添加满足条件的元素。迭代后,使用removeAll()传递的方法ArrayList和要删除的对象。

Is there a more efficient way to delete objects from an ArrayList?

有没有更有效的方法来删除对象ArrayList

采纳答案by Mnementh

Another way: The Iterator has an optional remove()-method, that is implemented for ArrayList. You can use it while iterating.

另一种方式:迭代器有一个可选的 remove() 方法,它是为 ArrayList 实现的。您可以在迭代时使用它。

I don't know though, which variant is the most performant, you should measure it.

我不知道哪个变体的性能最好,你应该衡量它。

starblue commented, that the complexity isn't good, and that's true (for removeAll() too), because ArrayList has to copy all elements, if in the middle is an element added or removed. For that cases should a LinkedList work better. But, as we all don't know your real use-cases the best is too measure all variants, to pick the best solution.

starblue 评论说,复杂性不好,这是真的(对于 removeAll() 也是如此),因为 ArrayList 必须复制所有元素,如果在中间添加或删除了一个元素。对于这种情况,LinkedList 应该更好地工作。但是,由于我们都不知道您的真实用例,因此最好的方法是衡量所有变体,以选择最佳解决方案。

回答by Bombe

Maybe Iterator's remove()method? The JDK's default collection classes should all creator iterators that support this method.

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

回答by RichardOD

You could iterate backwards and remove as you go through the ArrayList. This has the advantage of subsequent elements not needing to shift and is easier to program than moving forwards.

您可以在遍历 ArrayList 时向后迭代并删除。这具有后续元素不需要移动的优点,并且比向前移动更容易编程。

回答by Buhb

First, I'd make sure that this really is a performance bottleneck, otherwise I'd go with the solution that is cleanest and most expressive.

首先,我会确保这确实是一个性能瓶颈,否则我会选择最干净、最具表现力的解决方案。

If it IS a performance bottleneck, just try the different strategies and see what's the quickest. My bet is on creating a new ArrayList and puting the desired objects in that one, discarding the old ArrayList.

如果它是性能瓶颈,只需尝试不同的策略,看看什么是最快的。我的赌注是创建一个新的 ArrayList 并将所需的对象放入其中,丢弃旧的 ArrayList。

回答by Jesper

Obviously, of the two methods you mention number 1 is more efficient, since it only needs to go through the list once, while with method number 2 the list has to be traversed two times (first to find the elements to remove, and them to remove them).

显然,在您提到的两种方法中,第 1 种方法效率更高,因为它只需要遍历列表一次,而使用方法 2 则必须遍历列表两次(首先找到要删除的元素,然后将它们移到删除它们)。

Actually, removing a list of elements from another list is likely an algorithm that's worse than O(n) so method 2 is even worse.

实际上,从另一个列表中删除元素列表可能是一种比 O(n) 更糟糕的算法,因此方法 2 更糟糕。

The iterator method:

迭代器方法:

List data = ...;

for (Iterator i = data.iterator(); i.hasNext(); ) {
    Object element = i.next();

    if (!(...)) {
        i.remove();
    }
}

回答by gustafc

Most performant would, I guess, be using the listIteratormethod and do a reverse iteration:

我猜,最高效的人会使用该listIterator方法并进行反向迭代:

for (ListIterator<E> iter = list.listIterator(list.size()); iter.hasPrevious();){
    if (weWantToDelete(iter.previous()))  iter.remove();
}

Edit:Much later, one might also want to add the Java 8 way of removing elementsfrom a list (or any collection!) using a lambda or method reference. An in-place filterfor collections, if you like:

编辑:很久以后,人们可能还想添加Java 8使用 lambda 或方法引用从列表(或任何集合!)中删除元素的方法。filter集合的就地,如果你喜欢:

list.removeIf(e -> e.isBad() && e.shouldGoAway());

This is probably the best way to clean up a collection. Since it uses internal iteration, the collection implementation could take shortcuts to make it as fast as possible (for ArrayLists, it could minimize the amount of copying needed).

这可能是清理集合的最佳方式。由于它使用内部迭代,因此集合实现可以采取捷径使其尽可能快(对于ArrayLists,它可以最大限度地减少所需的复制量)。

回答by thomax

Unless you're positive that the issue you're facing is indeed a bottleneck, I would go for the readable

除非你确定你面临的问题确实是一个瓶颈,否则我会选择可读的

public ArrayList filterThings() {

    ArrayList pileOfThings;
    ArrayList filteredPileOfThings = new ArrayList();

    for (Thing thingy : pileOfThings) {
        if (thingy.property != 1) {
            filteredPileOfThings.add(thingy);
        }            
    }
    return filteredPileOfThings;
}

回答by Everyone

I'm good with Mnementh's recommentation.
Just one caveat though,

我对 Mnementh 的评论很满意。
不过只是一个警告,

 ConcurrentModificationException

Mind that you don't have more than one thread running. This exception could appear if more than one thread executes, and the threads are not well synchronized.

请注意,您运行的线程不会超过一个。如果执行多个线程,并且线程没有很好地同步,则可能会出现此异常。

回答by Stephen C

There is a hidden cost in removing elements from an ArrayList. Each time you delete an element, you need to move the elements to fill the "hole". On average, this will take N / 2assignments for a list with N elements.

从 ArrayList 中删除元素存在隐藏成本。每次删除元素时,都需要移动元素以填充“洞”。平均而言,这将对N / 2具有 N 个元素的列表进行分配。

So removing M elements from an N element ArrayList is O(M * N)on average. An O(N) solution involves creating a new list. For example.

所以从一个 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);
    }
}

If N is large, my guess is that this approach will be faster than the removeapproach for values of M as small as 3 or 4.

如果 N 很大,我的猜测是这种方法将比removeM 值小到 3 或 4的方法快。

But it is important to create newListlarge enough to hold all elements in listto avoid copying the backing array when it is expanded.

但是创建newList足够大以容纳所有元素list以避免在扩展时复制支持数组是很重要的。

回答by Stephen C

I have found an alternative faster solution:

我找到了另一种更快的解决方案:

  int j = 0;
  for (Iterator i = list.listIterator(); i.hasNext(); ) {
    j++;

    if (campo.getNome().equals(key)) {
       i.remove();
       i = list.listIterator(j);
    }
  }