Roshan
Roshan

Reputation: 2184

Filter object from List if filter condition is multiple and coming dynamically

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

Upvotes: 1

Views: 2182

Answers (2)

XiaFF
XiaFF

Reputation: 21

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

Upvotes: 2

charles-allen
charles-allen

Reputation: 4081

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

Upvotes: 4

Related Questions