如何使用谓词从已转换的集合中删除元素?

时间:2010-07-07 18:39:33

标签: guava predicates

如果我有ArrayList<Double> dblListPredicate<Double> IS_EVEN,我可以使用以下内容从dblList删除所有偶数元素:

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

如果dblList

之类的转换的结果
dblList = Lists.transform(intList, TO_DOUBLE)

这不再起作用,因为转换后的列表是不可变的: - )

任何解决方案?

6 个答案:

答案 0 :(得分:2)

Lists.transform()接受一个List并帮助返回RandomAccess列表的结果。 Iterables.transform()只接受Iterable,结果不是RandomAccess。最后,Iterables.removeIf(并且据我所知,这是Iterables中唯一的一个)在给定参数是RandomAccess的情况下进行优化,其中的一点是使算法线性而不是二次,例如想想如果你有一个很大的ArrayList(而不是一个应该更受欢迎的ArrayDeque)会发生什么,并且不断从它的开始移除元素直到它为空。

但是优化不依赖于迭代器remove(),而是依赖于List.set(),这在转换后的列表中是不可能的。如果要解决这个问题,我们需要另一个标记界面来表示“可选的set()实际上有效”。

所以你有的选择是:

  • 调用Iterables.removeIf()版本,并运行二次算法(如果列表很小或删除少量元素,则无关紧要)
  • 将列表复制到另一个支持所有可选操作的列表中,然后调用Iterables.removeIf()。

答案 1 :(得分:1)

以下方法应该有效,但我还没有尝试过。

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

checkCollection()方法生成未实现List的列表视图。 [相反,创建一个ForwardingCollection会更干净,但更冗长。]然后Collections2.filter()不会调用不支持的set()方法。

库代码可以更强大。 Iterables.removeIf()可以生成一个组合谓词,正如迈克尔D建议的那样,当传递一个转换后的列表时。但是,我们之前决定不通过添加那种特殊情况逻辑来使代码复杂化。

答案 2 :(得分:0)

也许:

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

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

答案 3 :(得分:0)

只要您不需要中间集合,就可以使用Predicates.compose()创建首先转换项目的谓词,然后计算转换项目的谓词。

例如,假设我有一个List&lt; Double&gt;从中我想删除整数部分均匀的所有项目。我已经有一个函数&lt; Double,Integer&gt;这给了我整数部分和一个谓词&lt;整数&gt;告诉我它是否均匀。

我可以使用它们来获取新的谓词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();

答案 4 :(得分:0)

经过一些尝试,我想我已经找到了它。)

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]

答案 5 :(得分:0)

我没有解决方案,而是Iterables.removeIf()Lists.TransformingRandomAccessList结合使用时发现某种问题。

转换后的列表实现RandomAccess,因此Iterables.removeIf()委托给Iterables.removeIfFromRandomAccessList(),这取决于不受支持的List.set()操作。 然而,调用Iterators.removeIf()会成功,因为Lists.TransformingRandomAccessList支持remove()操作。

见:Iterables:147

结论:instanceof RandomAccess不保证List.set()。

增加: 在特殊情况下,调用removeIfFromRandomAccessList()甚至可以工作: 当且仅当要擦除的元素在List的尾部形成一个紧凑的组或所有元素都被谓词覆盖。