Guava: Why is there no List.filter () function?

Is there a reason why there is

Lists.transform() 

but not

 Lists.filter() 

?

How to filter the list? I could use

 new ArrayList(Collection2.filter()) 

Of course, but this does not guarantee that my order will remain the same if I understood correctly.

+83
java list filter guava
Dec 10 '11 at 18:01
source share
5 answers

It was not implemented because it would expose a dangerous large number of slow methods, such as #get (index) in the returned list view (prompting for performance errors). And ListIterator will also be painful to implement (although I introduced the patch several years ago to cover this).

Since indexed methods cannot be efficient in the filtered form of a list, it is better to simply go with an Iterable filter that does not have them.

+54
Dec 10 '11 at 10:16
source share

You can use Iterables.filter , which will definitely maintain order.

Note that by creating a new list, you will copy elements (only links, of course) - so this will not be a real-time preview in the original list. Creating a view would be quite complicated - consider this situation:

 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); 

This would have to iterate over the entire source list, applying a filter to everything. I believe that this may require that the coincidence of predicates does not change over the lifetime of the view, but this would not be entirely satisfactory.

(Just guess, mind you. Perhaps one of Guavaโ€™s companions will beat the real reason :)

+36
Dec 10 '11 at 18:08
source share

I could use new List(Collection2.filter()) , of course, but in this way it did not guarantee that my order would remain the same.

This is not true. Collections2.filter() is a lazily evaluated function - it does not actually filter your collection until you start accessing the filtered version. For example, if you iterate over a filtered version, then the filtered items will exit the iterator in the same order as the original collection (except for those that were filtered, obviously).

You may have thought that it performs filtering in front, and then uploads the results to an arbitrary disordered collection of some form - this is not so.

So, if you use the output of Collections2.filter() as an input to a new list, then your original order will be saved.

Using static imports (and the Lists.newArrayList function), it gets pretty concise:

 List filteredList = newArrayList(filter(originalList, predicate)); 

Please note that until Collections2.filter eagerly Lists.newArrayList over the base collection, Lists.newArrayList will - it will extract all the elements of the filtered collection and copy them to the new ArrayList .

+28
Dec 10 '11 at 20:32
source share

As John mentioned, you can use Iterables.filter(..) or Collections2.filter(..) , and if you don't need live viewing, you can use ImmutableList.copyOf(Iterables.filter(..)) or Lists.newArrayList( Iterables.filter(..)) , and yes, the ordering will be preserved.

If you are really interested in why the part, you can visit http://code.google.com/p/guava-libraries/issues/detail?id=505 for more details.

+12
Dec 10 '11 at 20:25
source share

To summarize what others have said, you can easily create a common wrapper for filtering lists:

 public static <T> List<T> filter(Iterable<T> userLists, Predicate<T> predicate) { return Lists.newArrayList(Iterables.filter(userLists, predicate)); } 
+5
Sep 16 '14 at 9:24
source share



All Articles