Удаление элементов в foreach - PullRequest
0 голосов
/ 11 июня 2009

Разрешено ли вам удалять элемент из коллекции, которую вы сейчас повторяете в цикле foreach?

Если это так, что должно быть правильным поведением?

Ответы [ 9 ]

3 голосов
/ 11 июня 2009

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

Следовательно, самый безопасный подход - это цикл. Соберите ссылки на вещи, которые необходимо удалить, и затем используйте собранные ссылки для удаления элементов из исходной коллекции.

1 голос
/ 11 июня 2009

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

1 голос
/ 11 июня 2009

Как правило, изменение коллекции в цикле foreach является плохой идеей, поскольку ваше намерение неизвестно программе. Вы хотели перебрать все элементы перед изменением, или вы хотите, чтобы оно просто соответствовало новой конфигурации? А как насчет предметов, которые уже были пройдены?

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

1 голос
/ 11 июня 2009

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

0 голосов
/ 11 июня 2009

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

List<String> myList = ArrayList<String>();
Iterator<String> myIt = myList.iterator();

while (myIt.hasNext()) {
    myIt.remove();
}
0 голосов
/ 11 июня 2009

Нет, не стоит. Правильное поведение должно сигнализировать о том, что возникла потенциальная проблема параллелизма, однако это делается на выбранном вами языке (выбросить исключение, вернуть код ошибки, повысить () сигнал).

Если вы изменяете структуру данных во время итерации по ее элементам, итератор может перестать быть допустимым, что означает, что вы рискуете работать с объектами, которые больше не являются частью коллекции. Если вы хотите фильтровать элементы на основе более сложной нотации, вы можете сделать что-то вроде этого (в Java):

List<T> toFilter = ...;
List<T> shadow;
for ( T element : toFilter )
    if ( keep(element) )
         shadow.add(element);

/* If you'll work with toFilter in the same context as the filter */
toFilter = shadow;

/* Alternatively, if you want to modify toFilter in place, for instance if it's
 * been given as a method parameter
 */
toFilter.clear();
toFilter.addAll(shadow);
0 голосов
/ 11 июня 2009

повторяем в обратном направлении и удаляем элемент один за другим ... Это должно правильное решение.

0 голосов
/ 11 июня 2009

Просто используйте стандартный цикл for, перебирайте коллекцию элементов в обратном направлении, и у вас не должно возникнуть проблем с удалением элементов по ходу работы.

0 голосов
/ 11 июня 2009

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

...