Как получить список объектов с помощью нескольких комбинаций фильтров / предикатов в Java 8? - PullRequest
0 голосов
/ 27 января 2019

Мне нужна ваша помощь, чтобы выяснить, как лучше всего решить эту проблему в Java 8

У меня есть список объектов X, которые должны быть классифицированы.

Это мой набор правил:

ID  | Filtre1 | Filtre2 | Filtre3 | ValueToApply
1   |  'abc'  |  null   |  null   |  10
2   |  'abc'  |  'def'  |  null   |  25 
3   |  'abc'  |  null   |  'ghi'  |  20

Случай 1: у меня есть один объект X, который содержит (value1 = abc, value2 = def, value3 = ghi), поэтому код должен возвращать список с правилами 1, 2,3

Случай 2: у меня есть один объект X, который содержит (value1 = abc, value2 = def, value3 = hij), поэтому код должен вернуть список с правилами 1, 2

Спасибо

1 Ответ

0 голосов
/ 28 января 2019

Пока «лучший путь» очень расплывчатый.Вот одна интерпретация, которая, по крайней мере, является хорошей отправной точкой, объединяющей список правил для фильтрации полей в объектах, которые можно расширять, не ограничиваясь количеством полей или объектов, легко взаимозаменяемых типов и т. Д.

Сначала давайте определимнекоторые объекты данных для захвата модели данных:

static class Rule {
    final int id;
    final int valueToApply;
    final Predicate<String>[] valueFilters;

    public Rule(int id, int valueToApply, Predicate<String>... valueFilters) {
        this.id = id;
        this.valueToApply = valueToApply;
        this.valueFilters = valueFilters;
    }

    @Override
    public String toString() {
        return "Rule{id="+id+", valueToApply="+valueToApply+"}";
    }
}

static class X {
    final String[] values;

    X(String... values) {
        this.values = values;
    }
}

Затем основной метод, использующий их с предложенными в данных:

public static void main(String[] args) {
    X x1 = new X("abc", "def", "ghi");
    X x2 = new X("abc", "def", "hij");

    List<Rule> rules = new ArrayList<>(Arrays.asList(
            new Rule(1, 10, v->"abc".equals(v)),
            new Rule(2, 25, v->"abc".equals(v), v->"def".equals(v)),
            new Rule(3, 20, v->"abc".equals(v), v->true, v->"ghi".equals(v))
    ));

    Collection<Rule> rulesResult = classify(x1, rules);
    System.out.println("Case 1:"+rulesResult);
    rulesResult = classify(x2, rules);
    System.out.println("Case 2:"+rulesResult);
}

Ожидаемый результат:

Case 1:[Rule{id=1, valueToApply=10}, Rule{id=2, valueToApply=25}, Rule{id=3, valueToApply=20}]
Case 2:[Rule{id=1, valueToApply=10}, Rule{id=2, valueToApply=25}]

И «магия» метода классификации.

static Collection<Rule> classify(X x, Collection<Rule> rules) {
    List<Rule> result = new ArrayList<>();

    for (Rule rule : rules) {
        for (int i = 0; i < x.values.length; i++) {
            if (rule.valueFilters.length > i && !rule.valueFilters[i].test(x.values[i]))
                continue;
            if (i == x.values.length-1)
                result.add(rule);
        }
    }

    return result;
}

Ничего существенного, на что можно было бы обратить внимание.rule.valueFilters.length > i есть, поэтому вам не нужно указывать конечные фильтры в правилах, которые все возвращают true.

Я уверен, что можно использовать потоки, но читабельность будет сомнительной и, скорее всего, неэффективной дляпакетная работа, подобная этой, в которой нет раннего завершения / ленивых преимуществ eval.

Цикл над объектами класса X.

...