番石榴:为什么没有Lists.filter()函数?
有没有原因
Lists.transform()
但不是
Lists.filter()
?
如何正确过滤列表? 我可以使用
new ArrayList(Collection2.filter())
当然,但是这样做并不能保证我的订单保持不变,只要我理解正确。
它没有被实现,因为它会暴露大量的慢方法,例如返回的List视图上的#get(index)(引发性能错误)。 而且ListIterator也将是一个痛苦的实施(虽然我提交了一个补丁几年前,以弥补)。
由于索引方法在经过筛选的List视图中效率不高,因此最好使用过滤后的Iterable(不包含它们)。
你可以使用Iterables.filter
,它肯定会保持sorting。
请注意,通过构build新列表,您将复制元素(当然只是引用),因此它不会成为原始列表上的实时视图。 创build视图将是相当棘手的 – 考虑这种情况:
Predicate<StringBuilder> predicate = /* predicate returning whether the builder is empty */ List<StringBuilder> builders = Lists.newArrayList(); List<StringBuilder> view = Lists.filter(builders, predicate); for (int i = 0; i < 10000; i++) { builders.add(new StringBuilder()); } builders.get(8000).append("bar"); StringBuilder firstNonEmpty = view.get(0);
这将不得不遍历整个原始列表,将filter应用到一切。 我想这可能要求谓词匹配在视图的整个生命周期中不会改变,但是这并不是完全令人满意的。
(这只是猜测,介意你,也许其中一个番石榴维护者将切实的原因:)
我当然可以使用
new List(Collection2.filter())
,但是这样做并不能保证我的sorting保持不变。
这是不正确的。 Collections2.filter()
是一个懒惰的评估函数 – 它实际上并没有过滤你的集合,直到你开始访问过滤版本。 例如,如果迭代过滤版本,那么过滤后的元素将按照与原始集合相同的顺序从迭代器中popup(显然,将被滤除的元素减去)。
也许你在想,它是先过滤,然后把结果转储成任意的,无序的某种forms的集合 – 事实并非如此。
因此,如果您使用Collections2.filter()
的输出作为新列表的input,那么您的原始订单将保留。
使用静态导入(和Lists.newArrayList
函数),它变得相当简洁:
List filteredList = newArrayList(filter(originalList, predicate));
请注意,虽然Collections2.filter
不会急于迭代基础集合,但Lists.newArrayList
将会提取过滤集合的所有元素,并将它们复制到新的ArrayList
。
正如Jon所提到的,你可以使用Iterables.filter(..)
或Collections2.filter(..)
,如果你不需要实时视图,你可以使用ImmutableList.copyOf(Iterables.filter(..))
或者Lists.newArrayList( Iterables.filter(..))
和是的sorting将被维护。
如果您确实对部分内容感兴趣,可以访问http://code.google.com/p/guava-libraries/issues/detail?id=505了解更多详情。;
总结别人说的话,你可以很容易地创build一个通用的包装来过滤列表:
public static <T> List<T> filter(Iterable<T> userLists, Predicate<T> predicate) { return Lists.newArrayList(Iterables.filter(userLists, predicate)); }