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

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

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

Thedata это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, но не может понять, почему.

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

Ответы на вопрос(14)

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

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

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

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

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

Уже поздно, но это может сработать.

Iterator<YourObject> itr = yourList.iterator();

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

ArrayList.

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

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

for (int i = 0; i < data.size(); i++){
    if (data.get(i).getCaption().contains("_Hardi")){
        data.remove(i);
        i--;
    }
}
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

ого объекта итератора. Вот концепция. Предположим, что ваш arrayList содержит список имен:

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

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

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

пока вы выполняете итерацию по нему. Вместо этого используйте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 (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) (примерно). Таким образом, влияние на операцию удаления очень велико.

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

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();
    }
}

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

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

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

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

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

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

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

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

Решение Вопроса

от 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);
    }
 }
 Bigflow24 мая 2012 г., 16:07
Спасибо за это, а также за объяснение. Теперь я также знаю, почему он все время пропускал.
 Shirish Patel18 окт. 2018 г., 09:23
Что если я переинициализируюсь какdata = new ArrayList<>()

Ваш ответ на вопрос