简体   繁体   中英

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??

You can define a method as such that utilises partitioningBy internally:

static Map<Boolean, Set<Map.Entry<String, Boolean>>> partition(Map<String, Boolean> map){
      return map.entrySet()
                .stream()
                .collect(Collectors.partitioningBy(Map.Entry::getValue, 
                                                   Collectors.toSet()));
}

Now, you can do:

Map<Boolean, Set<Map.Entry<String, Boolean>>> firstResultSet = partition(map1);

Map<Boolean, Set<Map.Entry<String, Boolean>>> secondResultSet = partition(map2);

Calling firstResultSet.get(true) will return a set of map entries where each entry key has a corresponding value of true .

Conversely calling firstResultSet.get(false) will return a set of map entries where each entry key has a corresponding value of false .

The same can be done to the secondResultSet map in order to retrieve the corresponding set of map entries.

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM