使用谓词动态过滤List

Ste*_*eSt 0 java predicate guava

我有以下字符串列表:

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

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

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

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

return city == myStringVariable

我可以将该城市的论据提供给Predicate或以某种方式结合两个谓词吗?

Fra*_*eau 8

Guava Predicate通过Predicates帮助程序类提供了许多非常通用的s .

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

Predicate<String> myCity = Predicates.equalTo(myStringVariable);
Run Code Online (Sandbox Code Playgroud)

更新以回答评论中的问题:如何在列表不是Strings 时过滤,而是在具有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;
    }
    
    Run Code Online (Sandbox Code Playgroud)
  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();
    
    Run Code Online (Sandbox Code Playgroud)
  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();
    
    Run Code Online (Sandbox Code Playgroud)

但是,我不会equals()像评论中提到的那样覆盖,它可能过于具体,不能说2个实例SomeObject等于仅因为它们的属性之一.如果您需要在不同的上下文中过滤2个不同的属性,它不会扩展.

如果你的Java 8中,代码变得更加紧凑使用lambda表达式,你可以直接使用StreamAPI无论如何,所以你不需要番石榴.

  • 如果你重写你的类的equals方法(来自doc:`如果被测试的对象等于(),则返回一个谓词,如果给定的目标或两者都为null,则返回true.) (2认同)

Nee*_*eeL 5

您可以使用最终的 String 或 Predicate 的子类:

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

或者

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");
Run Code Online (Sandbox Code Playgroud)

正如 @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");
Run Code Online (Sandbox Code Playgroud)