Guava:Iterables.frequency(Iterable <T>,Predicate <T>)

12

在Iterable中确定满足Predicate条件的元素数量的方法真的不存在吗? 我这样做是正确的吗:

return Lists.newArrayList(Iterables.filter(iterable, predicate)).size()
如果是这样的话,没有提供方法的原因是什么?
Iterable.frequency(Iterable<T>, Predicate<T>)

干杯

3个回答

25
这可能更容易:
return Iterables.size(Iterables.filter(iterable, predicate));

避免分配所有数组内存。


这更好了。在内部,它创建一个计数器并遍历过滤后的元素一次。 - kungfoo
1
是的,这样做更好 - 但要注意,如果Iterable引用了一个有点动态的“集合”(比如数据库表),通常会得到一个不可靠的值。每次调用filter时,“size”可能会有所不同。它只是一个快照。 - Andreas Dolk
当然,但是其他解决方案如何避免这种情况呢?一般来说,如果集合正在改变,你所能期望的最好结果就是在调用开始和结束之间某个时间点上正确的值。在某些情况下,你甚至都无法得到这个结果 - 想象一下一个同时被修改的列表,经历以下状态:A,B,C -> B,C -> B,C,D列表从未有过大小为4,但是在迭代期间可能会计算出四个元素,因为如果并发修改发生在正确的时刻,你可以看到A和D。 - BeeOnRope

4
当可迭代对象是一个集合时,可以这样说:
return Collections2.filter(collection, predicate).size();

目前还没有太多人需要使用Iterable.frequency(iterable, predicate)方法。


3
这个过滤方法不会创建集合,而是创建一个新的Iterable并使用新的迭代器进行过滤,就像当你实际迭代Iterable时一样。因此,guava框架可以有一个frequency(Iterable, Predicate)方法,但是这个方法必须在内部创建迭代器才能获取迭代步数,并在之后将其丢弃。如果你的迭代器工作在动态集合上(比如数据库表),频率“大小”和过滤“大小”甚至可能是不同的。如果你需要迭代器和大小两者都要用到,那么可以将Iterable放入适当的集合中(freeze),并使用集合的size()方法。这保证了基于过滤后的Iterable的真实大小值。

我认为它被投票否决了,因为在初始代码中我就冻结了从应用过滤器后得到的集合,并使用size()方法对其进行了操作。最初的问题源于存在一个方法Iterables.frequency(Iterable<T>, Object o),该方法计算等于o的元素数量。 - kungfoo

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接