1

I have a requirement where I have to filter object from list based on multiple dynamic filter condition.

I have already written code by looping over objects and then all filter and returning false if any condition doesn't match. The code that I have written is as

    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 method is 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;
}

Is there any better way to achieve it if filters that I am getting is coming dynamically.

I have already seen some answer in stackoverflow as here ,but with no help

6
  • Are you using Java 8? Commented Aug 15, 2017 at 14:00
  • I can use that. But even with stream filter I am not able to think solution better then this. Commented Aug 15, 2017 at 14:01
  • Not a solution, but I would switch your conditional to avoid a potential NPE: if (!filterEntry.getValue().equals(employee.get(filterEntry.getKey()))) Commented Aug 15, 2017 at 14:15
  • @DanW , Yes I forgot to add that. Actually I am doing String Comparision with Apache StringUtils which is null safe. Commented Aug 15, 2017 at 14:18
  • @Roshan - You can convert your conditions into a single Predicate and then use Stream.filter() - see my answer. Commented Aug 15, 2017 at 14:45

2 Answers 2

4

Combine all filters as a single Predicate (using stream, reduce, and predicate composition):

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

Then just use Stream.filter()

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

Helper function:

private static Predicate<Map<String, String>> getAsPredicate(Map.Entry<String, String> filter) {
    return (Map<String, String> employee) -> employee.get(filter.getKey()).equals(filter.getValue());
}
Sign up to request clarification or add additional context in comments.

1 Comment

Thanks for this beautiful answer.
2

Maybe you can use for-loop with Stream:

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

3 Comments

Thanks , This is really helpfull. Good approach
@Roshan check the CodeConfident's answer - it's cleaner
@Xiaff - I actually enjoyed reading yours too; it's a style I wouldn't have thought of (you broadened my programming mind!)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.