【问题标题】:Filter object from List if filter condition is multiple and coming dynamically如果过滤条件是多个并且动态出现,则从列表中过滤对象
【发布时间】:2018-01-23 11:11:29
【问题描述】:

我有一个要求,我必须根据多个动态过滤条件从列表中过滤对象。

我已经编写了代码,通过循环遍历对象然后所有过滤器并在任何条件不匹配时返回 false。我写的代码是

    Map<String, String> obj1  = new HashMap<>();
    obj1.put("id", "1");
    obj1.put("name", "name1");
    obj1.put("dept", "IT");
    obj1.put("sex", "M");

    Map<String, String> obj2  = new HashMap<>();
    obj2.put("id", "2");
    obj2.put("name", "name2");
    obj2.put("dept", "IT");
    obj2.put("sex", "M");

    Map<String, String> obj3 = new HashMap<>();
    obj3.put("id", "3");
    obj3.put("name", "name3");
    obj3.put("dept", "DEV");
    obj3.put("sex", "F");

    ArrayList<Map<String, String>> employees = new ArrayList<>(Arrays.asList(obj1,obj2,obj3));

    Map<String, String> filterCondition = new HashMap<>();
    filterCondition.put("dept", "IT");
    filterCondition.put("sex", "M");

    List<Map<String, String>> filteredEmployee = new ArrayList<>();

    for(Map<String,String> employee:employees){
        if(isValid(filterCondition, employee)){
            filteredEmployee.add(employee);
        }
    }

    System.out.println(filteredEmployee);

isValid 方法为 as

private static boolean isValid(Map<String, String> filterCondition, Map<String, String> employee) {
    for(Entry<String, String> filterEntry:filterCondition.entrySet()){
        if(!employee.get(filterEntry.getKey()).equals(filterEntry.getValue())){
            return false;
        }
    }
    return true;
}

如果我得到的过滤器是动态的,有没有更好的方法来实现它。

我已经在 stackoverflow 中看到了一些答案为here,但没有任何帮助

【问题讨论】:

  • 您使用的是 Java 8 吗?
  • 我可以使用它。但即使使用流过滤器,我也无法比这更好地思考解决方案。
  • 不是解决方案,但我会切换您的条件以避免潜在的 NPE:if (!filterEntry.getValue().equals(employee.get(filterEntry.getKey())))
  • @DanW ,是的,我忘记添加了。实际上我正在使用 Apache StringUtils 进行字符串比较,它是空安全的。
  • @Roshan - 您可以将条件转换为单个谓词,然后使用 Stream.filter() - 请参阅我的答案。

标签: java java-8


【解决方案1】:

将所有过滤器组合为一个 Predicate(使用流、reduce 和 predicate 组合):

Predicate<Map<String, String>> allConditions = filterCondition
        .entrySet()
        .stream()
        .map(ThisClass::getAsPredicate)
        .reduce((employee) -> true, Predicate::and);

然后只需使用 Stream.filter()

List<Map<String, String>> filteredEmployees = employees
        .stream()
        .filter(allConditions)
        .collect(Collectors.toList());

辅助函数:

private static Predicate<Map<String, String>> getAsPredicate(Map.Entry<String, String> filter) {
    return (Map<String, String> employee) -> employee.get(filter.getKey()).equals(filter.getValue());
}

【讨论】:

  • 感谢您的精彩回答。
【解决方案2】:

也许你可以在 Stream 中使用 for 循环:

    Stream<Map<String, String>> employeeStream = employees.stream();
    for (Map.Entry<String, String> entry : filterCondition.entrySet()) {
        employeeStream = employeeStream.filter(map -> entry.getValue()
                                          .equals(map.get(entry.getKey())));
    }
    List<Map<String, String>> filteredEmployee = employeeStream.collect(Collectors.toList());

【讨论】:

  • 谢谢,这真的很有帮助。好方法
  • @Roshan 检查 CodeConfident 的答案 - 它更干净
  • @Xiaff - 实际上我也很喜欢阅读你的文章;这是我没想到的风格(你拓宽了我的编程思维!)
猜你喜欢
  • 1970-01-01
  • 2018-04-19
  • 1970-01-01
  • 1970-01-01
  • 2021-07-05
  • 2019-12-26
  • 2013-07-21
  • 1970-01-01
  • 2017-06-14
相关资源
最近更新 更多