2016-07-01 5 views
3

Я работаю над небольшим приложением, где я пытаюсь разместить объект (Property) в ArrayList<Property>. В основном я создаю функцию поиска, которая работает на Map того, что искать.Если заявление с неизвестным количеством условий

Например: Я хочу, чтобы найти все свойства с именем "12 Hello Lane", которые были перечислены в период между 2013 и 2015

Я бы тогда сделать вот так:

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 
... 

Мой вопрос, как я могу сделать это так, что я могу использовать один, если заявление, чтобы охватить все свойства? Что-то вроде:

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

Я не знаю, если я правильно формулируя это, но я надеюсь, что вы, ребята, я клоню.

EDIT: Я пытаюсь добиться эффекта if a AND b AND c.... Просто подумал, что я уточню, поскольку я вижу, что многие ответы дают нечто более похожее на OR.

ответ

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.

+0

Спасибо. Я проверю это утром (чувствуя себя немного уставшим ...). Но похоже, что это сработает ... – Riccorbypro

+0

@Riccorbypro Нет проблем! Нажмите на демонстрационную ссылку, вы сможете увидеть, что происходит, и если это то, что вы ищете. Доброй ночи! – dasblinkenlight

+0

Это сработало! Спасибо. – Riccorbypro

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 
    } 
} 
0

Из ваших требований, это звучит, как вам нужно, это какое-то предикат строителя. Вам нужно будет написать код, который создает эти предикаты, которые я покажу ниже, затем вы можете перебрать их и вызвать оценку. Я применил один из случаев, в котором вы нуждаетесь.

interface Predicate { 

    boolean evaluate(); 

} 

class StringComparePredicate implements Predicate { 

    final String key; 
    final String value; 

    StringComparePredicate(String key, String value) { 
     this.key = key; 
     this.value = value; 
    }  

    @Override 
    boolean evaluate() { 
     return this.key.equals(this.value); 
    } 
} 

и один для сравнения дат и т.д. Затем вы можете позвонить цикл и запустить оценки по каждому из предикатов.

0

я запутался сначала из-за двойного entender слова «собственности».Вы могли бы сделать еще один класс, называемый 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... 
} 

Итак в недвижимости вы можете хранить список 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. 
     } 
    } 
} 
+0

К сожалению, для этого потребуется большая переструктура моих объектов, так как мой объект «Свойство» в настоящее время имеет атрибуты в качестве переменных внутри класса объектов. Предполагаете ли вы, что у каждого свойства есть список атрибутов, каждый атрибут которого задан как ключ/значение? – Riccorbypro

+0

При повторном чтении я вижу, что этот подход равен выражению 'OR', а не' AND'. Я пытаюсь достичь «И». – Riccorbypro

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

Тогда вы будете иметь ряд matchers (адрес, год и т.д.) и фактический метод фильтра, который будет применять все те из условий к списку:

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)); 
+0

Я не уверен, что это будет работать правильно для того, что мне нужно, но я тоже проверю это. – Riccorbypro

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