2015-01-08 3 views
0

Я только что попал в Google Guava и кажется мощным инструментом, и я вижу, как вы можете использовать Predicates и фильтровать по определенному свойству. Как вы можете также предикатов цепи в FluentIterable. Мой вопрос - это лучший способ фильтрации для одного свойства.Google Guava - фильтр нескольких входов на одном объекте

Например, если у меня есть коллекция автомобилей. Как фильтровать Cars.getPaintColor(), чтобы дать мне автомобили, которые находятся в черном, красном и желтом? Создание 3 отдельных предикатов и использование FluentIterable кажется неуклюжим. Особенно в моем использовании, я мог бы хотеть, возможно, 10+ фильтров в одном и том же свойстве, и я бы не хотел создавать 10 Predicates.

Спасибо!

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

Поскольку я использую список, я использовал copyOf вместо of при создании ImmutableSet.

Я не уверен, что добавить второй параметр сочинения. Я предполагаю, что это что-то вроде этого ... в классе CarObj.

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

     // What do I put here? 
    } 
}; 
+0

Вы хотите отфильтровать одно значение свойства за раз (но с разными возможными значениями) или вы хотите разбить все ваши Автомобили на основе значения свойства? Вам либо нужен параметризованный «Predicate», либо просто извлечение «Function» (как упоминалось в ColinD) и 'Multimaps.index()'. –

+0

@FrankPavageau Я хочу фильтровать одно значение свойства с разностными возможными значениями, но я также хочу фильтровать другие свойства, которые имеют разные возможные значения. – Alan

ответ

3

Таким образом, чтобы проверить, если цвет краски один из черного, читать или желтый цвет, вы хотите создать Predicate, который проверяет, если набор содержит этот цвет:

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

Вы могли бы то сочинить, что с Function<Car, PaintColor>, которая возвращает цвет краски свойство вашего класса:

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

Edit:

По Car.GET_PAINT_COLOR_FUNCTION Я просто имею в виду что-то вроде этого:

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

Как я уже говорил в комментариях, вы можете адаптировать, что для ваших реальных типов, как это необходимо. Например, сделайте вместо этого Function<CarObj, String>.

+0

@Alan: Оттуда вы просто передаете предикат 'filter'. – ColinD

+0

Что делать, если цвета не являются перечислением? – Alan

+0

@Alan: На самом деле не имеет значения, как вы создаете 'Collection', который вы передаете' Predicates.in'. – ColinD

1

Альтернативой скомпоновать извлечения Function<Car, PaintColor> с Predicates.in() как предложено ColinD, чтобы написать ваш параметризованных Predicate<Car>:

public class CarPaintColorPredicate implements Predicate<Car> { 
    private final PaintColor paintColor; 

    public CarPaintColorPredicate(PaintColor paintColor) { 
     this.paintColor = paintColor; 
    } 

    @Override 
    public boolean apply(@Nullable Car input) { 
     return input != null && input.getPaintColor() == paintColor; 
    } 
} 

, которые затем можно использовать непосредственно:

FluentIterable.from(cars) 
     .filter(new CarPaintColorPredicate(PaintColor.RED)) 
     .toList(); 

или комбинировать для нескольких цвета:

FluentIterable.from(cars) 
     .filter(Predicates.or(
      new CarPaintColorPredicate(PaintColor.RED), 
      new CarPaintColorPredicate(PaintColor.BLACK))) 
     .toList(); 

или даже комбинировать с другими типами сказуемых:

FluentIterable.from(cars) 
     .filter(new CarPaintColorPredicate(PaintColor.RED)) 
     .filter(new CarMakePredicate("Ferrari")) 
     .toList(); 

быть полным, версия с Function<Car, PaintColor> выглядит следующим образом:

public enum CarPaintColorFunction implements Function<Car, PaintColor> { 
    INSTANCE; 

    @Override 
    public PaintColor apply(@Nullable Car input) { 
     return input == null ? null : input.getPaintColor(); 
    } 
} 

Function просто возвращает значение свойства , который затем сравнивается с коллекцией (на наш взгляд, Set) принятых значений через композицию Predicate:

FluentIterable.from(cars) 
     .filter(Predicates.compose(
      Predicates.in(Sets.immutableEnumSet(PaintColor.RED, PaintColor.BLACK)), 
      CarPaintColorFunction.INSTANCE)) 
     .toList(); 

Все, что действительно объяснено на странице Functional Explained в Guava Wiki.

+0

Спасибо, Фрэнк. Можете ли вы привести пример того, как работает 'Function ' с 'Predicates.in()'? – Alan

+0

Здесь вы найдете дополнительный пример. –

Смежные вопросы