Чем заменить цикл For-Each для фильтрации? - PullRequest
2 голосов
/ 01 октября 2009

Хотя цикл for-each имеет много преимуществ, но проблема в том, что он не работает, когда вы хотите отфильтровать (фильтрация означает удаление элемента из List) List, можете ли вы порадовать его любой заменой, поскольку даже обход через Index не хороший вариант ..

Ответы [ 4 ]

11 голосов
/ 01 октября 2009

Что вы подразумеваете под «фильтрацией»? Удаление определенных элементов из списка? Если это так, вы можете использовать итератор :

for(Iterator<MyElement> it = list.iterator(); it.hasNext(); ) {
    MyElement element = it.next();
    if (some condition) {
      it.remove();
    }
}

Обновление (на основе комментариев):

Рассмотрим следующий пример, чтобы проиллюстрировать, как работает итератор. Допустим, у нас есть список, содержащий «А» и «В»:

A A B B A

Мы хотим удалить все эти надоедливые B s. Итак, используя вышеуказанный цикл, код будет работать следующим образом:

  1. hasNext ()? Да. следующий(). element указывает на 1-й А.
  2. hasNext ()? Да. следующий(). element указывает на 2-й А.
  3. hasNext ()? Да. следующий(). element указывает на 1-й Б. удалить (). Счетчик итератора НЕ изменяется, он по-прежнему указывает на то место, где был B (технически это не совсем правильно, но логически так оно и работает). Если бы вы теперь вызывали метод remove () снова, вы получите исключение (потому что элемента списка больше нет).
  4. hasNext ()? Да. следующий(). element указывает на 2-й B. Остальное такое же, как # 3
  5. hasNext ()? Да. следующий(). element указывает на 3-й А.
  6. hasNext ()? Нет, мы закончили. Список теперь имеет 3 элемента.

Update # 2 : remove() Операция действительно необязательна на итераторе - но только потому, что она необязательна для базовой коллекции. Нижняя строка здесь - если ваша коллекция поддерживает это (и все коллекции в Java Collection Framework), то и итератор тоже. Если ваша коллекция не поддерживает ее, вам все равно не повезло.

0 голосов
/ 01 октября 2009

Если вам, как и мне, не нравится модифицировать коллекцию при итерации по ее элементам или если итератор просто не предоставляет реализацию для удаления, вы можете использовать временную коллекцию, чтобы просто собрать элементы, которые вы хотите удалить , Да, да, он менее эффективен по сравнению с модификацией итератора, но мне понятнее понять, что происходит:

List<Object> data = getListFromSomewhere();
List<Object> filter = new ArrayList<Object>();

// create Filter
for (Object item: data) {
  if (throwAway(item)) {
    filter.add(item);
  }
}

// use Filter
for (Object item:filter) {
  data.remove(item);
}

filter.clear();
filter = null;
0 голосов
/ 01 октября 2009

Я успешно использовал

filter(java.util.Collection collection, Predicate predicate) 

метод CollectionUtils в общих коллекциях.

http://commons.apache.org/collections/api-2.1.1/org/apache/commons/collections/CollectionUtils.html#filter(java.util.Collection,%20org.apache.commons.collections.Predicate)

0 голосов
/ 01 октября 2009

Ответ ChssPly76 - правильный подход, но я заинтригован вашим мнением о том, что «переход по индексу не является хорошим вариантом». Во многих случаях - частый случай, в частности, ArrayList - это чрезвычайно эффективно. (На самом деле, в случае с arraylist, я полагаю, что повторные вызовы get(i++) незначительно быстрее, чем использование Итератора, хотя далеко не достаточно, чтобы жертвовать удобочитаемостью).

Вообще говоря, если рассматриваемый объект реализует java.util.RandomAccess , то доступ к последовательным элементам через индекс должен быть примерно такой же, как при использовании итератора. Если это не так (например, LinkedList будет хорошим контрпримером), то вы правы; но не отклоняйте опцию из-под контроля.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...