Java 从 ArrayList 中删除元素
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/19376969/
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
Removing elements from ArrayList
提问by Dropout
I'm trying to remove certain elements from an ArrayList<String>
我正在尝试从 ArrayList<String>
for(int i=0; i<myList.size(); i++)
{
if(myList.get(i).contains("foo"))
{
myList.remove(i);
}
}
This however leaves "empty spaces" in my list. I would like the list to leave out the empty elements and after iterating through it shrink to neccessary size.
然而,这在我的列表中留下了“空白空间”。我希望列表省略空元素,并在遍历它后缩小到必要的大小。
Is there a smart way to do this without having to switch to a LinkedList
?
有没有一种聪明的方法可以做到这一点而不必切换到 a LinkedList
?
采纳答案by Jon Skeet
This however leaves "empty spaces" in my list.
然而,这在我的列表中留下了“空白空间”。
No, it doesn't. It removes entries from the list completely. Other elements are moved appropriately. What it doesdo with the way you've written is skip the check for the next entry... because that will have "shuffled down" to be element i
, but you'll next look at element i + 1
.
不,它没有。它从列表中完全删除条目。其他元素适当移动。它不会做你所写的方法是跳过下一个入口检查......因为这将有“洗牌下来”是元素i
,但你会在元素接下来看看i + 1
。
One simple way to avoid this is to work backwards instead:
避免这种情况的一种简单方法是向后工作:
for (int i = myList.size() - 1; i >= 0; i--) {
if (myList.get(i).contains("foo")) {
myList.remove(i);
}
}
Or use an iterator as noted in other answers, of course. Both will work - the above code may be slightly more efficient if you're removing multiple entries, however, as there'll be less to shift by the time you get to the start. It's unlikely that that will be significant.
当然,或者使用其他答案中提到的迭代器。两者都可以工作 - 如果您要删除多个条目,上面的代码可能会稍微高效一些,但是,因为在您开始时移动的次数会减少。这不太可能是重要的。
It's unfortunate that in order to use the iterator solution you have to use the iterator explicitly- you can't remove from a collection while using an enhanced for loop.
不幸的是,为了使用迭代器解决方案,您必须显式使用迭代器- 在使用增强的 for 循环时不能从集合中删除。
回答by Xavi López
Use an Iterator
and call Iterator.remove()
instead.
改用Iterator
and 调用Iterator.remove()
。
Iterator it = myList.iterator();
while(it.hasNext()) {
if (it.next().contains("foo")) {
it.remove();
}
}
This way you will also avoid trouble for reducing the size of the list while relying on it as an exit condition to your loop, and accessing it using indexes that might be varying.
通过这种方式,您还可以避免减少列表大小的麻烦,同时依赖它作为循环的退出条件,并使用可能变化的索引访问它。
Of course iterating through the list backwards will also work.
当然,向后遍历列表也可以。
回答by Konstantin Yovkov
The smart way you're looking for is the Iterator
interface. For example:
您正在寻找的智能方式是Iterator
界面。例如:
Iterator<String> it = list.iterator();
while (it.hasNext()) {
String nextItem = it.next();
if (nextItem.contains("foo")) {
it.remove();
}
}
回答by nullptr
After you remove list will automatically shrink.
删除列表后会自动缩小。
Suppose you remove element at index 3, that element will be removed, list will shrink and the element that was at index 4 will have index 3 after remove.
假设您删除索引 3 处的元素,该元素将被删除,列表将缩小,删除后位于索引 4 的元素将具有索引 3。
You should do this:
你应该做这个:
for(int i=0; i<myList.size(); i++)
{
if(myList.get(i).contains("foo"))
{
myList.remove(i);
// as element is removed, next element will have decremented index
i--;
}
}
回答by Admit
Influenced by Scala
and functional programming, I would recommend you to just copy your values to new list for immutability.
受Scala
函数式编程的影响,我建议您将值复制到新列表中以实现不变性。
List<String> filtered = new ArrayList<String>();
for (String s : myList) {
if (!s.contains("foo")) {
filtered.add(s);
}
}
I would also recommend 2 libs to try out: Guava
and lambdaj
我还会推荐 2 个库来尝试:Guava
和lambdaj
回答by erencan
ArrayList maintains an array behind the scene. I want to deep into source code of java.util.ArrayList
and java.util.LinkedList
.
ArrayList 在幕后维护一个数组。我想深入研究java.util.ArrayList
和的源代码java.util.LinkedList
。
First of all ArrayList maintains an array behind the scenes. Once you create an ArrayList instance it creates an array whose size is 10 and it grows while the elements inserted. It is size grow to 3(size)/2 +1
首先 ArrayList 在幕后维护一个数组。创建 ArrayList 实例后,它会创建一个大小为 10 的数组,并在插入元素时增长。它是大小增长到 3(size)/2 +1
Here is the source code.
这是源代码。
Default size of arrat list. Look at constructer code.
arrat 列表的默认大小。查看构造函数代码。
public ArrayList() {
this(10);
}
its size grows to 3(size)/2 + 1. here is the source code. ArrayList#ensureCapacitymethod is called insite ArrayList#add
它的大小增长到 3(size)/2 + 1。这里是源代码。ArrayList#ensureCapacity方法在现场调用ArrayList#add
public void ensureCapacity(int minCapacity) {
modCount++;
int oldCapacity = elementData.length;
if (minCapacity > oldCapacity) {
Object oldData[] = elementData;
int newCapacity = (oldCapacity * 3)/2 + 1;
if (newCapacity < minCapacity)
newCapacity = minCapacity;
// minCapacity is usually close to size, so this is a win:
elementData = Arrays.copyOf(elementData, newCapacity);
}
}
When you remove any item from ArrayList. It is removed from the list and other list items is shifted down to the removed items location. Take special attention, reference to this object is set to null and object become eligible to GC, but there is still a reference allocated for ArrayList. The array size behind the ArrayList is same.
当您从 ArrayList 中删除任何项目时。它从列表中删除,其他列表项下移到删除项的位置。需要特别注意的是,这个对象的引用被设置为空并且对象有资格进入 GC,但仍然有一个引用分配给 ArrayList。ArrayList 后面的数组大小相同。
Here is the source code
这是源代码
public E remove(int index) {
rangeCheck(index);
modCount++;
E oldValue = elementData(index);
int numMoved = size - index - 1;
if (numMoved > 0)
System.arraycopy(elementData, index+1, elementData, index,
numMoved);
elementData[--size] = null; // Let gc do its work
return oldValue;
}
As Jon Skeet answered, when an item is removed next item to removed item will be in the removed items location.
正如 Jon Skeet 所回答的那样,当一个项目被移除时,下一个被移除项目将在移除项目位置。
However, allocated memory space is the same after removal. java.util.LinkedList is stands for this issue. All items inside LinkedList is dynamicly allocated and deallocated (It is GC's work, of course)
但是,移除后分配的内存空间是一样的。java.util.LinkedList 代表这个问题。LinkedList 中的所有项都是动态分配和释放的(当然这是 GC 的工作)
java.util.LinkedList maintains a doubly linked listbehind the scenes. Each add and remove operations changes the memory space used by LinkedList. The item is removed and reference to item from its previous and next items is updated.
java.util.LinkedList在幕后维护一个双向链表。每次添加和删除操作都会更改 LinkedList 使用的内存空间。该项目被删除,并更新其上一个和下一个项目对项目的引用。
private Entry<E> entry(int index) {
if (index < 0 || index >= size)
throw new IndexOutOfBoundsException("Index: "+index+
", Size: "+size);
Entry<E> e = header;
if (index < (size >> 1)) {
for (int i = 0; i <= index; i++)
e = e.next;
} else {
for (int i = size; i > index; i--)
e = e.previous;
}
return e;
}
I assume that GC collects items as soon as it is removed, i know it is not certain. But removed memory location is a candidate to GC. Please be careful about the reference to the object and the object itself.
我认为 GC 会在删除后立即收集项目,我知道这并不确定。但是删除的内存位置是 GC 的候选者。请注意对对象的引用和对象本身。
Both ArrayList and LinkedList removes items while ArrayList still stores a reference for object types and memory space for primitive types, Linked list also removes references and memory space. At least, references and memory also will be eligible to GC.
ArrayList 和 LinkedList 都删除项,而 ArrayList 仍然存储对象类型的引用和原始类型的内存空间,Linked list 还删除引用和内存空间。至少,引用和内存也将有资格进行 GC。
回答by Joshnee
No it won't leaves "empty spaces" in your list, but you will miss removing all required elements from your list.
不,它不会在您的列表中留下“空白空间”,但您会错过从列表中删除所有必需元素。
Lets try to explain with below example. I am having a ArrayList with 4 elements. (a,b,c,d).
让我们试着用下面的例子来解释。我有一个包含 4 个元素的 ArrayList。(A B C D)。
for (int i = 0; i < list.size(); i++) {
if (((String) list.get(i)).contains("c")) {
list.remove(i);
}
if (((String) list.get(i)).contains("b")) {
list.remove(i);
}
}
for (int i = 0; i < list.size(); i++) {
System.out.print(list.get(i)+" ");
}
Result: a c d
结果:acd
When traversing the list in forward direction, I tried removing elements (c,b) but still element c is present in my list.
当向前遍历列表时,我尝试删除元素 (c,b) 但元素 c 仍然存在于我的列表中。
To avoid this we can traverse in backward direction like below.
为了避免这种情况,我们可以像下面这样向后遍历。
for (int i = list.size() - 1; i >= 0; i--) {
if (((String) list.get(i)).contains("a")) {
list.remove(i);
}
if (((String) list.get(i)).contains("c")) {
list.remove(i);
}
}
for (int i = 0; i < list.size(); i++) {
System.out.print(list.get(i) + " ");
}
Result: b d
结果:bd