使用谓词动态过滤List

时间:2014-06-27 14:24:52

标签: java guava predicate

我有以下字符串列表:

  

{"纽约","伦敦","巴黎","柏林","纽约" }

我正在尝试使用Guava库,我希望以这样的方式过滤此列表,我将只获得将等于我将提供的字符串的字符串。如果我有一个固定的价值,那就说“纽约"我会做以下事情:

Predicate<String> myCity = new Predicate<String>() {
    @Override public boolean apply(String city) {
        return city == "New York";
    }               
};

但是,如果我希望return语句是这样的:

  

return city == myStringVariable

我可以将该城市的参数提供给Predicate,还是以某种方式合并两个谓词?

3 个答案:

答案 0 :(得分:8)

Guava通过Predicates助手类提供了许多非常通用的Predicate

要过滤相等(对于String或任何其他对象),它会提供equalTo()谓词:

Predicate<String> myCity = Predicates.equalTo(myStringVariable);

更新以回答评论中的问题:如何在列表不是String时过滤,而是过滤具有String属性的对象。

您有几种选择,具体取决于您已有的选项:

  1. 使用命令性代码

    对于一次性使用,除非您使用Java 8,否则使用功能构造有点冗长。请参阅Wiki中的FunctionalExplained页面。

    private List<SomeObject> filterOnMyCity(List<SomeObject> list,
                                            String value) {
        List<SomeObject> result = new ArrayList<>();
        for (SomeObject o : list) {
            if (value.equals(o.getMyCity())) {
                result.add(o);
            }
        }
        return result;
    }
    
  2. 使用ad-hoc谓词

    class MyCityPredicate implements Predicate<SomeObject> {
         private final String value;
    
         public MyCityPredicate(String value) {
             this.value = value;
         }
    
         @Override
         public boolean apply(@Nullable SomeObject input) {
             return input != null && value.equals(input.getPropertyX());
         }
    }
    
    return FluentIterable.from(list)
            .filter(new MyCityPredicate(myStringVariable))
            .toList();
    
  3. 使用现有的Function

    class MyCityFunction implements Function<SomeObject, String> {
         @Override
         public String apply(@Nullable SomeObject input) {
             return input == null ? null : input.getPropertyX();
         }
    }
    
    return FluentIterable.from(list)
            .filter(Predicates.compose(
                    Predicates.equalTo(myStringVariable),
                    new MyCityFunction()))
            .toList();
    
  4. 但是,我不会覆盖评论中提到的equals(),它可能过于具体,不能说SomeObject的2个实例等于它们的属性之一。如果您需要在不同的上下文中过滤2个不同的属性,它不会扩展。

    如果你有Java 8,使用lambda表达式代码变得更加紧凑,你可以直接使用Stream API,因此你不需要Guava 。 / p>

答案 1 :(得分:3)

要么使用Predicate的最终String或子类:

final String testStr = textbox.getText(); //for example
Predicate<String> myCity = new Predicate<String>() {
    @Override public boolean apply(String city) {
        return city.equals(testStr);
    }               
};

public class CityPredicate implements Predicate<String>{
    String cityName;
    public CityPredicate(String cityName){
        this.cityName = cityName;
    }
    @Override public boolean apply(String city) {
        return city.equals(cityName);
    } 
}
//Use example :
Predicate<String> myCity = new CityPredicate("New York");

正如@Sotirios Delimanolis告诉你的那样,总是将String与equals()进行比较

编辑:Frank Pavageau解决方案的示例: 鉴于你的班级:

public class City{
    String cityName;
    public City(String cityName){
        this.cityName=cityName;
    }

    @Override
    public boolean equals(Object obj) {
        if(obj instanceof String){
            return cityName.equals(obj);
        }
        return false;
    }
}

List<City> cities =  Lists.newArrayList(new City("New York"),new City("Chicago"));
Predicate<String> myCityPredicate = Predicates.equalTo("New York");
final List<City> res = Lists.newArrayList(Iterables.filter(cities , myCityPredicate));
//res.size() will be 1 and containing only your City("New York")
//To check whether it is present you can do :
final boolean isIn = Predicates.in(cities).apply("New York");

答案 2 :(得分:2)

您可以通过关闭其他变量来构造谓词

final String cityName = "New York";
Predicate<String> myCity = new Predicate<String>() {
    @Override public boolean apply(String city) {
        return city.equals(cityName);
    }               
};

请注意我如何比较字符串与equals方法而不是==引用相等运算符。请参阅下文了解原因。

How do I compare strings in Java?