具有多个条件的过滤列表

时间:2018-07-26 13:59:46

标签: algorithm filter

我有一个名为Data的类;我有一个包含一些数据的列表,以及一个使用数据类的属性过滤该列表的函数

if a,b,c  filter words are not empty => data object must have these 3
if a,b are not empty => data object must have these 2
if a,c are not empty => data object must have these 2
if b,c are not empty => data object must have these 2
if a is not empty    => data object must have this
if b is not empty    => data object must have this
if c is not empty    => data object must have this

如您所见,我编写了一个可以完成其工作的代码,但我不喜欢我的算法,因此您可以建议我使用更智能的算法,因为如果类的字段计数增加,我需要编写新的ifs。 (我正在使用Java,但我不会添加Java标记,也许有一个不错的伪代码,但Javas函数也被接受了)

public class Data {

    private String a;
    private String b;
    private String c;

    private String getA() {
        return a;
    }

    private String getB() {
        return b;
    }

    private String getC() {
        return c;
    }


    private List<Data> filterData(List<Data> datas, String a, String b, String c) {
        List<Data> result = new ArrayList<>();

        for (Data data : datas) {
            if (a != null && data.getA().equals(a) && b != null && data.getB().equals(b) && c != null && data.getC().equals(c)) {
                result.add(data);
            } else if (a != null && data.getA().equals(a) && b != null && data.getB().equals(b)) {
                result.add(data);
            } else if (a != null && data.getA().equals(a) && c != null && data.getC().equals(c)) {
                result.add(data);
            } else if (b != null && data.getB().equals(b) && c != null && data.getC().equals(c)) {
                result.add(data);
            } else if (a != null && data.getA().equals(a)) {
                result.add(data);
            } else if (b != null && data.getB().equals(b)) {
                result.add(data);
            } else if (c != null && data.getC().equals(c)) {
                result.add(data);
            } else {
                return null;
            }
        }
        return result;
    }
}

假设您拥有汽车列表,并且汽车类别具有颜色(a),型号年份(b),燃料类型(c)假定它们不是字符串枚举,或者您不需要比较其范围内的型号年份

  • 如果用户想要白色(2011年,柴油),则必须添加具有这3个属性的汽车,这意味着您不能添加白色(2012年,柴油),因为用户想要2011年
    • 用户可能想要白色,null,null,那么您只需要检查带有白色的汽车

3 个答案:

答案 0 :(得分:1)

这是一种更通用的方法:将要过滤的字符串添加到数组,然后以相同顺序添加数据中的值。然后,我们可以利用它们具有相同索引的事实,以更通用的方式对它们进行比较。

List<String> filterBy = new List<String>{a, b, c};
for (Data data : datas) {
    Boolean shouldAdd = true;
    List<String> values = new List<String>{data.getA(), data.getB(), data.getC()};
    for (Integer i = 0; i < filterBy.size(); i++) {
        if (filterBy[i] != null && filterBy[i].equals(values[i]) == false) {
            shouldAdd = false;
            break;
        }
    }
    if (shouldAdd) {
        result.add(data);
    }
} 

答案 1 :(得分:1)

如果您改变了病情,则可以大大减少if检查的次数。目前,您的状况(拆分了7次if检查)大致如下:

(a & b & c) | (b & c) | (a & c) | (a & b) | a | b | c

abc中的每个对应于x != null && data.getX().equals(x)

如果将那些组件更改为a & b & c,即元素为null或匹配,则可以简化为x == null || data.getX().equals(x)。您也可以将此方法单独使用,以使代码更清晰。另外,您可以将循环和if检查为Stream.filter

    private boolean matches(Object x, Object y) {
        return x == null || x.equals(y);
    }

    private List<Data> filterData(List<Data> datas, String a, String b, String c) {
        return datas.stream()
                .filter(d -> matches(a, d.getA()))
                .filter(d -> matches(b, d.getB()))
                .filter(d -> matches(c, d.getC()))
                .collect(Collectors.toList());
    }

注意:1)我将data.getX().equals(x)更改为x.equals(data.getX()),因为您已经知道x!= null,但是getX()可能为空。另外,如果所有过滤器均为if,则您最后的null检查将null添加到列表中,而不是data。我以为这是个错误。

答案 2 :(得分:0)

我相信这就是您想要的组合。尽管您的描述不明确,但是您现有的代码与此不匹配。 (正如@juvian所说,您目前写的最后3个条件涵盖了前4个条件。)

private List<Data> filterData(List<Data> datas, String a, String b, String c) {
    List<Data> result = new ArrayList<>();

    for (Data data : datas) {
        if (! data.getA().equals(a == null ? data.getA() : a)) {
            // Filtered out
        }
        else if (! data.getB().equals(b == null ? data.getB() : b)) {
            // Filtered out
        }
        else if (! data.getC().equals(c == null ? data.getC() : c)) {
            // Filtered out
        }
        else {
            result.add(data);
        }
    }
    return result;
}