Вопрос по android, java – Удалить данные из ArrayList с помощью цикла For

16

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

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   ответов
40

от 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);
    }
 }
Спасибо за это, а также за объяснение. Теперь я также знаю, почему он все время пропускал. Bigflow
Что если я переинициализируюсь какdata = new ArrayList<>() Shirish Patel
19

пока вы выполняете итерацию по нему. Вместо этого используйтеIterator.remove() нравится

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

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

Вот как легко обойти это: (обратный отсчет, а не вверх)


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

4

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

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

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

4

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

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

for (int i = 0; i < data.size(); i++){
    if (data.get(i).getCaption().contains("_Hardi")){
        data.remove(i);
        i--;
    }
}
3
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) (примерно). Таким образом, влияние на операцию удаления очень велико.

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

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

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

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

ArrayList.

2

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

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

2
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

2

ого объекта итератора. Вот концепция. Предположим, что ваш 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
2

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

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

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

1

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

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

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

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

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

Похожие вопросы