如果声明具有未知数量的条件

时间:2016-07-01 18:54:27

标签: java if-statement dictionary

我正在开发一个小应用程序,我试图将一个对象(Property)放入ArrayList<Property>。基本上我正在制作一个搜索功能,它在Map搜索的内容上运行。

例如:我想搜索2013年至2015年间列出的名称为"12 Hello Lane"的所有房产。

我会这样做:

for (Property p : properties){
    if (p.getName().equals("12 Hello Lane") && p.getListingDate().getYear() >=2013 && p.getListingDate().getYear() <= 2015){
        //Add to list
    }
}

问题在于,我传递的Map属性要进行比较,关键是方法名称,值是期望值。换句话说:

Key: "getName"
Value: "12 Hello Lane"
Key: "getYear"
Value: 2013-2015
...

我的问题是如何制作它以便我可以使用单个if语句来涵盖所有属性?类似的东西:

for (Property p : properties){
    if (p.getClass().getMethod(options.getKey()) == options.getValue()){
        //Add to list
    }
}

我不知道我是否正确地表达了这一点,但我希望你们能让我的漂移。

编辑:我正在努力实现if a AND b AND c...的效果。只是想我会澄清,因为我看到很多答案都提供了类似于OR的内容。

5 个答案:

答案 0 :(得分:1)

好的,因为所有的答案都试图做出魔术......这是我的建议。

您真正想要的是Matcher

每个匹配器看起来像这样......例如,匹配名称:

private static Matcher<Property> withName(final String name) {
    return new BaseMatcher<Property>() {

        public void describeTo(Description description) {
            description.appendText("Matches property name to ").appendValue(name);
        }

        public boolean matches(Object o) {
            Property p = (Property) o;
            return p.name.equals(name);
        }
    };
}

然后您将拥有一些匹配器(用于地址,年份等)以及将所有这些标准应用于列表的实际过滤方法:

public List<Property> filter(Matcher<Property>... matchers) {
    List<Property> valid = new ArrayList<Property>(); //valid ones to return
    propertyLoop: for (Property property : propertyList) {
        for (Matcher<Property> matcher : matchers) {
            if (matcher.matches(property)) {
                valid.add(property);
            } else {
                continue propertyLoop;
        }
    }
    return valid;
}

因此,您的最终代码与此类似:

List<Property> machingProperties = filter(withName("12 Hello Lane"), withYear(2012, 2015));

答案 1 :(得分:0)

有时我只是想知道这些情况是如何存在的。 这是一般的想法:

for (Property p: properties) {
    boolean shouldAdd = true;
    for (String method: options.keySet()) {
        if (p.getClass().getMethod(method).invoke(p) != options.get(key)) { 
            shouldAdd = false;
            break;
        }
    }
    if (shouldAdd) {
       //add to list 
    }
}

答案 2 :(得分:0)

根据您的要求,听起来您需要的是某种谓词构建器。你需要编写一些代码来创建我在下面显示的这些谓词,然后你可以遍历它们并调用evaluate。我已经实现了你需要的一个案例。

force

和一个用于比较日期等。然后你可以调用你的for循环并在每个谓词上运行evaluate。

答案 3 :(得分:0)

你非常接近:

  • 您的方法相当于OR,而不是AND。如果你想要一个AND,做一个标志,在循环中设置它,并在循环结束后检查它
  • 您没有正确地调用反射。

以下是您应该如何做到的:

List<Data> allItems = ...
List<Data> filtered = new ArrayList<>();
for (Data d : allItems) {
    boolean allPass = true;
    for (Map.Entry<String,String> entry : propertyMap.entrySet()) {
        Method m = d.getClass().getMethod(entry.getKey());
        if (m == null || !entry.getValue().equals(m.invoke(d))){
            allPass = false;
            break;
        }
    }
    if (allPass) {
        filtered.add(d);
    }
}

Demo.

答案 4 :(得分:0)

起初我很困惑,因为&#34; Property&#34;这个词的双关语。您可以创建另一个名为 PropertyAttribute 的类:

public class PropertyAttribute {
    private String name;
    private Object value;

    public PropertyAttribute(String name, Object value) {
        this.name = name;
        this.value = value;
    }

    // Applicable getters and setters...
}

然后在 Property 中,您可以存储 PropertyAttributes 列表:

public class Property {
    public List<PropertyAttribute> attributes = new ArrayList<PropertyAttribute>();

    public Property() {
        // Add to attributes, like:
        attributes.add(new PropertyAttribute("name", "12 Hello Lane"));
        attributes.add(new PropertyAttribute("year", "2013 - 2015"));
    }
}

然后最后你可以搜索:

for(Property p : properties) {
     for(PropertyAttribute attr : p.attributes) {
         if(options.getKey() == attr.getName() && options.getValue() == attr.getValue) {
             // add to list.
         }
     }
}