Почему это не для цикла работы?

1

Поэтому мне нужно создать класс под названием mylistofstrings, который является именно тем, чем он звучит, массивом строк. Один из методов, который я должен написать, - это сохранить весь метод, который сохраняет только строки в списке, которые равны строке, введенной в качестве параметра. Кажется, что цикл for пропускает половину вещей, которые он должен удалить, любые идеи, почему? Метод размера просто возвращает количество элементов в списке и является простым для публикации.

public boolean retain(String string) {
     if (string == null) {
        throw new NullPointerException();
     }
     MyListOfStrings temp= new MyListOfStrings(this);
     int t=this.size();
     for (int i=0;i<this.size;i++){
         if (string.equals(temp.get(i))!=true){
             this.remove(i);
         }
     }
     return t<this.size();

Здесь метод get:

public String get(int index) {
    if (index < 0 || index >= size) {
        throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
    }
    return strings[index];
}

и метод удаления:

public String remove(int index) {
    if (index < 0 || index >= size) {
        throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
    }
    String temp = strings[index]; // Save to return at end
    System.arraycopy(strings, index + 1, strings, index, size - index - 1);
    strings[size - 1] = null;
    size--;
    return temp;
}
Теги:
for-loop

5 ответов

3

Вы изменяете содержимое массива, итерации по нему. При удалении элемента в позиции x элемент в позиции x + 1 получит новую позицию x, но поскольку x уже посещен циклом, следующей итерацией будет позиция x + 1, а элемент, который теперь удерживает позицию x будет пропущен.

Вам нужно сделать что-то вроде показанного здесь: удаление элементов из списка в java

Т.е. реализовать Iterable и удалить элементы с помощью Iterator

  • 0
    Но разве я не исправлю это, создав новый временный класс и повторив это?
  • 0
    Нет, потому что вы используете один и тот же индекс как временный, так и фактический. Как только элемент будет удален, они будут не синхронизированы (поэтому индекс x в temp не обязательно совпадает с индексом x в этом).
Показать ещё 2 комментария
1

Как только вы начнете изменять один из ваших контейнеров, они больше не параллельны, поэтому вы не удаляете правильные элементы.

Вы можете сделать это так:

int i = 0;
while (i < this.size) {
    if (!string.equals(strings[i])) {
         remove(i);
    } else {
         ++i;
    }
}

Обратите внимание, что когда вы удаляете элемент i, следующие элементы перемещаются вниз, а следующий элемент теперь находится в позиции i, поэтому, если вы увеличиваете i вы пройдете мимо него.

0

Похож на эту линию -

 MyListOfStrings temp= new MyListOfStrings(this);

копирует ссылку списка ввода, а не создает дублирующий список.

Как результат, вы удаляете текущую запись, а затем пропускаете следующую запись (которая теперь является текущей), потому что новый объект ссылается на одни и те же базовые данные.

Вы можете сделать список индексов для удаления, а затем удалить их в конце цикла. Конечно, вы должны удалить в обратном порядке, чтобы исключить такую же проблему.

0

Для удаления объектов из списка при итерации по нему лучше использовать/реализовать Iterator для вашего списка.

Однако, если вы хотите сделать это без Итератора, вы можете сделать это, уменьшив i-Variable на 1 каждый раз, когда вы удаляете строку из списка:

 for (int i=0;i<this.size;i++){
     if (string.equals(temp.get(i))!=true){
         this.remove(i);
         i--;
     }
 }

Это необходимо, потому что вы копируете я + 1-элемент в i-Position, который, как вам известно, нужно снова проверить.

0

Вы не должны вызывать операции редактирования во время итерации. Рассмотрим этот список:

1: "1"
2: "2"
3: "3"
4: "4"

Теперь вы хотите сохранить "1" и начать итерацию:

Первый шаг:

1: "1" <- do nothing
2: "2"
3: "3"
4: "4"

Шаг второй

1: "1"
2: "2" <- remove
3: "3"
4: "4"

результатом будет

1: "1"
2: "3"
3: "4"

Шаг третий

1: "1"
2: "3"
3: "4" <- remove

конечный результат

1: "1"
2: "3"

даже с вашим templist это случай, потому что индекс все еще увеличивается. На шаге 3 вы можете сравнить с "3" от своего templist, но удалить "4" из своего фактического списка.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню