Как удалить элементы из преобразованной коллекции, используя предикат? - PullRequest
2 голосов
/ 07 июля 2010

Если у меня есть ArrayList<Double> dblList и Predicate<Double> IS_EVEN, я могу удалить все четные элементы из dblList, используя:

Collections2.filter(dblList, IS_EVEN).clear()

, если dblList, однако, является результатом преобразования, подобного

dblList = Lists.transform(intList, TO_DOUBLE)

это больше не работает, поскольку преобразованный список неизменен: -)

Любое решение?

Ответы [ 6 ]

2 голосов
/ 08 июля 2010

Lists.transform () принимает список и услужливо возвращает результат, который является RandomAccess списком. Iterables.transform () принимает только Iterable, и результатом является не RandomAccess.Наконец, Iterables.removeIf (и, насколько я вижу, это единственный в Iterables) имеет оптимизацию в случае, если заданным аргументом является RandomAccess, суть которого состоит в том, чтобы вместо этого сделать алгоритм линейнымнапример, подумайте, что произойдет, если у вас большой ArrayList (а не ArrayDeque - это должно быть более популярно) и вы продолжаете удалять элементы с начала до его пустого.

Но оптимизация зависит не от итератораremove (), но в List.set () , что не может быть поддержано в преобразованном списке.Если бы это было исправлено, нам понадобился бы другой интерфейс маркера, чтобы обозначить, что «необязательный set () действительно работает».

Итак, у вас есть следующие варианты:

  • ВызовIterables.removeIf () и запустите квадратичный алгоритм (не имеет значения, если ваш список небольшой или вы удалили несколько элементов)
  • Скопируйте список в другой список, который поддерживает все необязательные операции, затем вызовите Iterables.removeIf ().
1 голос
/ 08 июля 2010

Следующий подход должен работать, хотя я еще не пробовал.

Collection<Double> dblCollection =
    Collections.checkedCollection(dblList, Double.class);
Collections2.filter(dblCollection, IS_EVEN).clear();

Метод checkCollection () генерирует представление списка, которое не реализует List.[Было бы чище, но более многословно создавать вместо этого ForwardingCollection.] Тогда Collections2.filter () не будет вызывать неподдерживаемый метод set ().

Код библиотеки можно сделать более устойчивымIterables.removeIf () может генерировать составленный предикат, как предположил Майкл Д., при передаче преобразованного списка.Однако ранее мы решили не усложнять код, добавив специальную логику такого рода.

0 голосов
/ 08 июля 2010

У меня нет решения, вместо этого я нашел какую-то проблему с Iterables.removeIf() в сочетании с Lists.TransformingRandomAccessList.

Преобразованный список реализует RandomAccess, поэтому Iterables.removeIf() делегирует Iterables.removeIfFromRandomAccessList(), что зависит от неподдерживаемой операции List.set (). Однако вызов Iterators.removeIf() будет успешным, поскольку операция удаления () поддерживается Lists.TransformingRandomAccessList.

см .: итераций: 147

Вывод: instanceof RandomAccess не гарантирует List.set ().

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

0 голосов
/ 08 июля 2010

После некоторых попыток, я думаю, я нашел это:)

final ArrayList<Integer> ints = Lists.newArrayList(1, 2, 3, 4, 5);
Iterables.removeIf(Iterables.transform(ints, intoDouble()), even());
System.out.println(ints);

[1,3,5]
0 голосов
/ 08 июля 2010

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

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

Я могу использовать их для получения нового предиката, INTEGER_PART_IS_EVEN

Predicate<Double> INTEGER_PART_IS_EVEN = Predicates.compose(IS_EVEN, DOUBLE_TO_INTEGER);
Collections2.filter(dblList, INTEGER_PART_IS_EVEN).clear();
0 голосов
/ 07 июля 2010

Может быть:

Collection<Double> odds = Collections2.filter(dblList, Predicates.not(IS_EVEN));

или

dblList = Lists.newArrayList(Lists.transform(intList, TO_DOUBLE));
Collections2.filter(dblList, IS_EVEN).clear();
...