collectionsfilterguavaandroid-guava

Google Guava - Filter Multiple Inputs on Single Property


I just got into Google Guava and it seems like a powerful tool and I see how you can use Predicates and filter by a specific property. How you can also chain predicates in FluentIterable My question is what's the best way to filter for a single property.

For example, if I have a collection of Cars. How do I filter the Cars.getPaintColor() to give me cars that are in Black, Red, and Yellow? Creating 3 separate predicates and using FluentIterable seems clumsy. Especially in my use, I could want possibly 10+ filters on the same property and I wouldn't want to create 10 Predicates.

Thanks you!

        List<String> colorList = (List<String>)filterCriteria.get("Color");
        List<String> makeList = (List<String>)filterCriteria.get("Make");
        List<String> rimSizeList = (List<String>)filterCriteria.get("RimSize");

        Predicate<String> predColor = Predicates.in(ImmutableSet.copyOf(colorList));
        Predicate<CarObj> predDirection2 = Predicates.compose(predColor ,[????] );

        Predicate<String> predMakeList  = Predicates.in(ImmutableSet.copyOf(makeList));
        Predicate<CarObj> predMakeList2 = Predicates.compose(predMakeList, [????] );

        Predicate<String> predRimSize = Predicates.in(ImmutableSet.copyOf(rimSizeList));
        Predicate<CarObj> predRimSize2 = Predicates.compose(predRimSize, [????] );

        Collection<CarObj> filtered = FluentIterable.from(mAllCars)
                .filter(predDirection2)
                .filter(predMakeList2)
                .filter(predRimSize2)
                .toList();

Since I am using an List, I used copyOf instead of of when creating ImmutableSet.

I am not sure what to put in the second parameter of the compose. I am guessing it is something like this... in the CarObj class.

static Predicate<CarObj> byColor= new Predicate<CarObj>() {
    public boolean apply(CarObj input) {

        // What do I put here?
    }
};

Solution

  • So, to check if a paint color is one of black, read or yellow, you'd want to create a Predicate that checks if a set contains that color:

    Predicate<PaintColor> p = Predicates.in(ImmutableSet.of(
        PaintColor.RED, PaintColor.BLACK, PaintColor.YELLOW));
    

    You could then compose that with a Function<Car, PaintColor> that returns the paint color property of your class:

    Predicate<Car> p2 = Predicates.compose(p, Car.GET_PAINT_COLOR_FUNCTION);
    

    Edit:

    By Car.GET_PAINT_COLOR_FUNCTION I just mean something like this:

    public static final Function<Car, PaintColor> GET_PAINT_COLOR_FUNCTION =
        new Function<Car, PaintColor>() {
          @Override public PaintColor apply(Car car) {
            return car.getPaintColor();
          }
        });
    

    As I said in the comments, you can adapt that to your actual types as needed. For example, make it a Function<CarObj, String> instead.