Удаление данных из ArrayList с помощью цикла For-loop

У меня странная проблема. Я думал, что это будет стоить мне несколько минут, но сейчас я боюсь несколько часов … Вот что я получил:

for (int i = 0; i < size; i++){ if (data.get(i).getCaption().contains("_Hardi")){ data.remove(i); } } 

data – это ArrayList. В ArrayList я получил несколько строк (всего 14 или около того) и 9 из них получил имя _Hardi.

И с приведенным выше кодом я хочу удалить их. Если я replace data.remove(i); С System.out.println то он выдает что-то 9 раз, что хорошо, потому что _Hardi находится в ArrayList 9 раз.

Но когда я использую data.remove(i); То он не удаляет все 9, но только несколько. Я сделал несколько тестов, и я также видел следующее:

Когда я переименую строки: Hardi1 Hardi2 Hardi3 Hardi4 Hardi5 Hardi6

Затем он удаляет только четные числа (1, 3, 5 и т. Д.). Он все время пропускает 1, но не может понять, почему.

Кто-нибудь знает, как это исправить? Или, может быть, еще один способ их удалить?

Спасибо, Bigflow

Solutions Collecting From Web of "Удаление данных из ArrayList с помощью цикла For-loop"

Проблема здесь в том, что вы повторяете от 0 до размера и внутри цикла вы удаляете элементы . Удаление элементов уменьшит размер списка, который не удастся при попытке получить доступ к индексам, размер которых превышает эффективный размер (размер после удаленных элементов).

Для этого есть два подхода.

Удалите использование итератора, если вы не хотите иметь дело с индексом.

 for (Iterator<Object> it = data.iterator(); it.hasNext();) { if (it.next().getCaption().contains("_Hardi")) { it.remove(); } } 

Иначе, удалите с конца.

 for (int i = size-1; i >= 0; i--){ if (data.get(i).getCaption().contains("_Hardi")){ data.remove(i); } } 

Вы не должны удалять элементы из списка, пока вы перебираете его. Вместо этого используйте Iterator.remove() как:

 for (Iterator<Object> it = list.iterator(); it.hasNext();) { if ( condition is true ) { it.remove(); } } 

Каждый раз, когда вы удаляете элемент, вы меняете индекс перед ним (поэтому, когда вы удаляете список [1], список [2] становится списком [1], следовательно, пропускается.

Вот очень простой способ: (вместо обратного отсчета)

for(int i = list.size() - 1; i>=0; i--) { if(condition...) list.remove(i); }
for(int i = list.size() - 1; i>=0; i--) { if(condition...) list.remove(i); } 

Это имеет смысл, если вы это продумаете. Скажем, у вас есть список [A, B, C] . Первый проход через цикл, i == 0 . Вы видите элемент A а затем удалите его, поэтому список теперь [B, C] , а элемент 0 – B Теперь вы увеличиваете i в конце цикла, так что вы смотрите на list[1] который является C

Одним из решений является уменьшение i всякий раз, когда вы удаляете элемент, чтобы он «отменял» последующий приращение. Лучшим решением, как указано выше, является использование Iterator<T> который имеет встроенную функцию remove() .

Говоря в целом, это хорошая идея, когда вы сталкиваетесь с такой проблемой, чтобы вытащить лист бумаги и притвориться, что вы компьютер, – пройдите через каждый шаг цикла, записывая все переменные, когда вы идете. Это сделало бы «пропуск» ясным.

 for (Iterator<Object> it = data.iterator(); it.hasNext();) { if ( it.getCaption().contains("_Hardi")) { it.remove(); // performance is low O(n) } } 

Если операция удаления требуется в списке в списке. Лучше вы используете LinkedList, который дает лучшую производительность Big O(1) (примерно).

Где в ArrayList – O(n) (грубо). Так что удар очень высок при удалении операции.

Потому что, когда вы удаляете элемент из списка, элементы списка перемещаются вверх. Поэтому, если вы удалите первый элемент, то есть при индексе 0, элемент в индексе 1 будет смещен в индекс 0, но ваш счетчик циклов будет увеличиваться на каждой итерации. Поэтому вместо получения обновленного 0-го элемента индекса вы получаете 1-й элемент индекса. Поэтому просто уменьшайте счетчик на каждый раз, когда вы удаляете элемент из своего списка.

Вы можете использовать приведенный ниже код, чтобы он работал нормально:

 for (int i = 0; i < data.size(); i++){ if (data.get(i).getCaption().contains("_Hardi")){ data.remove(i); i--; } } 

Это поздно, но это может сработать для кого-то.

 Iterator<YourObject> itr = yourList.iterator(); // remove all data which you want while (itr.hasNext()) { YourObject object= itr.next(); if (Your Statement) // for ex :object.AutoID == 0 && object.LineDeleted == true { itr.remove(); } } 

Это происходит потому, что, удалив элементы, вы изменяете индекс ArrayList .

Поскольку ваш индекс больше не подходит, как только вы удаляете значение

Кроме того, вы не сможете перейти к size так как если вы удалите один элемент, размер изменится.

Вы можете использовать iterator для достижения этого.

Можно также упомянуть, что вы также можете использовать это, используя обычный цикл while:

 int i = 0; while (i < data.size()) { if (data.get(i).getCaption().contains("_Hardi")) data.remove(i); else i++; } 

Обратите внимание, что data.size() нужно вызывать каждый раз в цикле, иначе вы получите исключение IndexOutOfBoundsException , поскольку каждый удаленный элемент изменяет исходный размер вашего списка.

 import java.util.ArrayList; public class IteratorSample { public static void main(String[] args) { // TODO Auto-generated method stub ArrayList<Integer> al = new ArrayList<Integer>(); al.add(1); al.add(2); al.add(3); al.add(4); System.out.println("before removal!!"); displayList(al); for(int i = al.size()-1; i >= 0; i--){ if(al.get(i)==4){ al.remove(i); } } System.out.println("after removal!!"); displayList(al); } private static void displayList(ArrayList<Integer> al) { for(int a:al){ System.out.println(a); } } } 

вывод:

Перед тем удаление !! 1 2 3 4

После снят !! 1 2 3

Я не понимаю, почему это решение является лучшим для большинства людей.

 for (Iterator<Object> it = data.iterator(); it.hasNext();) { if (it.next().getCaption().contains("_Hardi")) { it.remove(); } } 

Третий аргумент пуст, потому что был перенесен в следующую строку. Кроме того, it.next() не только увеличивает переменную цикла цикла, но и использует для получения данных. Для меня использование for цикла вводит в заблуждение. Почему вы не используете while ?

 Iterator<Object> it = data.iterator(); while (it.hasNext()) { Object obj = it.next(); if (obj.getCaption().contains("_Hardi")) { it.remove(); } } 

Существует более простой способ решить эту проблему без создания нового объекта итератора. Вот концепция. Предположим, что ваш массивList содержит список имен:

 names = [James, Marshall, Susie, Audrey, Matt, Carl]; 

Чтобы удалить все из Susie forward, просто получите индекс Susie и назначьте его новой переменной:

 int location = names.indexOf(Susie);//index equals 2 

Теперь, когда у вас есть индекс, скажите java, чтобы подсчитать количество раз, когда вы хотите удалить значения из списка arrayList:

 for (int i = 0; i < 3; i++) { //remove Susie through Carl names.remove(names.get(location));//remove the value at index 2 } 

Каждый раз, когда выполняется значение цикла, arrayList уменьшается по длине. Поскольку вы установили значение индекса и подсчитываете количество раз, чтобы удалить значения, вы все настроены. Ниже приведен пример вывода после каждого прохода:

  [2] names = [James, Marshall, Susie, Audrey, Matt, Carl];//first pass to get index and i = 0 [2] names = [James, Marshall, Audrey, Matt, Carl];//after first pass arrayList decreased and Audrey is now at index 2 and i = 1 [2] names = [James, Marshall, Matt, Carl];//Matt is now at index 2 and i = 2 [2] names = [James, Marshall, Carl];//Carl is now at index 3 and i = 3 names = [James, Marshall,]; //for loop ends 

Вот фрагмент того, как может выглядеть ваш последний метод:

 public void remove_user(String name) { int location = names.indexOf(name); //assign the int value of name to location if (names.remove(name)==true) { for (int i = 0; i < 7; i++) { names.remove(names.get(location)); }//end if print(name + " is no longer in the Group."); }//end method