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

JavaListFilterGuava

Java Problem Overview


Is there a reason there's

Lists.transform()

but no

Lists.filter()

?

How do I filter a list correctly? I could use

new ArrayList(Collection2.filter())

of course, but this way it's not guaranteed that my ordering stays the same, if I understand correctly.

Java Solutions


Solution 1 - Java

It wasn't implemented because it would expose a perilous large number of slow methods, such as #get(index) on the returned List view (inviting performance bugs). And ListIterator would be a pain to implement as well (though I submitted a patch years ago to cover that).

Since indexed methods can't be efficient in the filtered List view, it's better to just go with a filtered Iterable, which doesn't have them.

Solution 2 - Java

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

Note that by constructing a new list, you'll be copying the elements (just references, of course) - so it won't be a live view onto the original list. Creating a view would be pretty tricky - 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);

That would have to iterate over the whole original list, applying the filter to everything. I suppose it could require that the predicate matching didn't change over the lifetime of the view, but that would be not-entirely-satisfactory.

(This is just guessing, mind you. Maybe one of the Guava maintainers will chip in with the real reason :)

Solution 3 - Java

>I could use new List(Collection2.filter()) of course, but this way it's not guaranteed that my ordering stays the same.

This isn't true. Collections2.filter() is a lazily-evaluated function - it doesn't actually filter your collection until you start accessing the filtered version. For example, if you iterate over the filtered version, then the filtered elements will pop out of the iterator in the same order as your original collection (minus the ones filtered out, obviously).

Perhaps you were thinking that it does the filtering up front, then dumps the results into an arbitrary, unordered Collection of some form - it doesn't.

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

Using static imports (and the Lists.newArrayList function), it becomes fairly succinct:

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

Note that while Collections2.filter will not eagerly iterate over the underlying collection, Lists.newArrayList will - it will extract all elements of the filtered collection and copy them into a new ArrayList.

Solution 4 - Java

As mentioned by Jon, you can use Iterables.filter(..) or Collections2.filter(..) and if you don't need a live view you can use ImmutableList.copyOf(Iterables.filter(..)) or Lists.newArrayList( Iterables.filter(..)) and yes ordering will be maintained.

If you are really interested in why part, you can visit https://github.com/google/guava/issues/505 for more details.

Solution 5 - Java

Summing up what the others said, you can easily create a generic wrapper to filter lists:

public static <T> List<T> filter(Iterable<T> userLists, Predicate<T> predicate) {
    return Lists.newArrayList(Iterables.filter(userLists, predicate));
}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionFabian ZeindlView Question on Stackoverflow
Solution 1 - JavaDimitris AndreouView Answer on Stackoverflow
Solution 2 - JavaJon SkeetView Answer on Stackoverflow
Solution 3 - JavaskaffmanView Answer on Stackoverflow
Solution 4 - JavaPremrajView Answer on Stackoverflow
Solution 5 - JavaHolger BrandlView Answer on Stackoverflow