Search code examples
collectionsjava-8predicate

Java8: Use filters/predicates along with disjunction


There are two maps with same structure say map1 and map2 having structure as Map<String, Boolean>.

Map 1 contains following items:
("i1", True),("i2", True), ("i3", False), ("i4", True)
Map 2 contains following items:
("i1", True),("i2", False), ("i3", True), ("i5", True)

I want two kinds of information:
Information1: map1TrueMoreThanMap2True = 2
The map1TrueMoreThanMap2True is 2 because we are comparing map entries.
In this case the diff between map1 and map2 is:
Map1 - ("i2", True),("i4", True)

Information2: map1FalseMoreThanMap2False = 1
In this case the diff between map1 and map2 is:
Map1 - ("i3", False)

I am achieving this by writing below code:

 Map<String, Boolean> trueCountMap1 = map1.entrySet().stream()
                .filter(p -> p.getValue() == Boolean.TRUE)
                .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));

        Map<String, Boolean> trueCountMap2 = map2.entrySet().stream()
                .filter(p -> p.getValue() == Boolean.TRUE)
                .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));

        Map<String, Boolean> falseCountMap1 = map1.entrySet().stream()
                .filter(p -> p.getValue() == Boolean.FALSE)
                .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));

        Map<String, Boolean> falseCountMap2 = map2.entrySet().stream()
                .filter(p -> p.getValue() == Boolean.FALSE)
                .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
        map1TrueMoreThanMap2True = (CollectionUtils.disjunction(trueCountMap1.entrySet(), trueCountMap2.entrySet())
                .size())/2;
        map1FalseMoreThanMap2False = (CollectionUtils
                .disjunction(falseCountMap1.entrySet(), falseCountMap2.entrySet()).size())/2;

i think the above code is verbose. Is there a better way of doing it??


Solution

  • As far as I understood, you want to know, how many entries of map1 map to true (resp. false) and differ from the entries of map2. This doesn’t work by halving the disjunction’s size. It would work when all keys are guaranteed to be the same, but in your example data, there are different keys, "i4" only present in map1 and "i5" only present in map2, and it looks like pur coincidence that both map to the same value. As soon as either maps to a different value, your approach would fail.

    It’s much simpler to straight-forwardly implement the “how many entries of map1 map to true (resp. false) and differ from the entries of map2” instead of dealing with set operations:

    int map1TrueMoreThanMap2True   = (int)map1.entrySet().stream()
        .filter(e ->  e.getValue() && !map2.getOrDefault(e.getKey(), false))
        .count();
    int map1FalseMoreThanMap2False = (int)map1.entrySet().stream()
        .filter(e -> !e.getValue() && map2.getOrDefault(e.getKey(), true))
        .count();
    

    It’s possible to do this in one Stream operation, if you wish:

    Map<Boolean,Long> result = map1.entrySet().stream()
        .filter(e -> e.getValue() ^ map2.getOrDefault(e.getKey(), !e.getValue()))
        .collect(Collectors.partitioningBy(Map.Entry::getValue, Collectors.counting()));
    int map1TrueMoreThanMap2True   = result.get(true).intValue();
    int map1FalseMoreThanMap2False = result.get(false).intValue();