Удалить данные из 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, но не может понять, почему.

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

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

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

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

 for (Iterator 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 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 который имеет встроенную функцию remove() .

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

 for (Iterator 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--; } } 

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

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

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

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

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

 Iterator itr = yourList.iterator(); // remove the objects from list while (itr.hasNext()) { YourObject object = itr.next(); if (Your Statement) // id == 0 { itr.remove(); } } 

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

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

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

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

 import java.util.ArrayList; public class IteratorSample { public static void main(String[] args) { // TODO Auto-generated method stub ArrayList al = new ArrayList(); 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 al) { for(int a:al){ System.out.println(a); } } } 

вывод:

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

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

Существует более простой способ решить эту проблему без создания нового объекта iteratorа. Вот концепция. Предположим, что ваш массив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 

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

 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 

Это общая проблема при использовании Arraylists, и это происходит из-за того, что длина (размер) Arraylist может измениться. При удалении изменяется размер; поэтому после первой итерации ваш код переходит в режим haywire. Лучшим советом является либо использование Iterator, либо цикл со спины, я рекомендую цикл backword, хотя, поскольку я считаю, что он менее сложный и он все еще отлично работает с множеством элементов:

 //Let's decrement! for(int i = size-1; i >= 0; i--){ if (data.get(i).getCaption().contains("_Hardi")){ data.remove(i); } } 

Еще ваш старый код, только зацикленный по-другому!

Надеюсь, это поможет…

Веселая кодировка !!!

В дополнение к существующим ответам вы также можете использовать обычный цикл while с условным шагом:

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

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

  • Размеры динамических массивов Java?
  • Что делает оператор «+ =» в Java?
  • Почему объект Object.toString () по умолчанию содержит hash-код?
  • Переменная Java, помещенная в стек или кучу
  • В чем смысл $ в имени переменной?
  • Рассчитать количество будних дней между двумя датами в Java
  • Выполните еще одну банку в программе java
  • Android написать в папку sd card
  • java, расширяющий class с конструктором основного classа имеет параметр
  • URLConnection getContentLength () возвращает отрицательное значение
  • Динамические имена переменных Java
  • Давайте будем гением компьютера.