SkyBlackHawk
SkyBlackHawk

Reputation: 127

Extract submap from a map that contains only duplicate values

I'm searching for an optimal or subpotimal solution for below problem:

Hp: We have a Java8 Map: Map<Integer, Object>: {0 -> object0, 1 -> object0, 2->object1, ...., n->objectN}

Goal: Solution to return a Map (a submap) that contains only key,value elements of original map with same objects: Map<Integer, Object>: {0 -> object0, 1 -> object0}

I found a solution to get a List of duplicate but I don't find a solution to get a new Map with only duplicated values.

Thanks for support

Upvotes: 2

Views: 579

Answers (2)

Nowhere Man
Nowhere Man

Reputation: 19565

A straightforward solution would be:

  1. Build a temporary inverted map Map<Object, List<Integer>>
  2. Filter the inverted map to keep only duplicates
  3. Use flatMap to restore initial Map<Integer, Object>
Map<Integer, Object> map = Map.of(
    0, "object0", 1, "object0", 2, "objectA", 3, "objectZ", 4, "objectZ"
);
System.out.println(map);

Map<Integer, Object> filtered = map.entrySet().stream()
            .collect(Collectors.groupingBy(
                Map.Entry::getValue, 
                Collectors.mapping(Map.Entry::getKey, Collectors.toList())
            ))
            .entrySet().stream() // Stream<Map.Entry<Object, List<Integer>>>
            .filter(e -> e.getValue().size() > 1) // keep duplicates
            .flatMap(e -> e.getValue().stream().map(v -> Map.entry(v, e.getKey())))
            .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
System.out.println(filtered);

Output:

{0=object0, 1=object0, 2=objectA, 3=objectZ, 4=objectZ}
{0=object0, 1=object0, 3=objectZ, 4=objectZ}

Update

Simpler solution by @Andreas suggestion would be:

Map<Integer, Object> filtered2 = map.entrySet().stream()
            .collect(Collectors.groupingBy(Map.Entry::getValue))
            .entrySet().stream() // Stream<Map.Entry<Object, List<Map.Entry<Integer, Object>>>
            .filter(e -> e.getValue().size() > 1) // keep duplicates
            .flatMap(e -> e.getValue().stream())
            .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
System.out.println(filtered2);

Output is the same as above:

{0=object0, 1=object0, 3=objectZ, 4=objectZ}

Upvotes: 1

ETO
ETO

Reputation: 7279

You can try this:

Map<Object, Map<String, Object>> subMaps = 
    map.entrySet()
       .stream()
       .collect(groupingBy(Map.Entry::getValue,
                           toMap(Map.Entry::getKey, Map.Entry::getValue)));

This will return you a map of maps.

So if you want the submap containing only object0 do this:

Map<String, Object> subMap = subMaps.get(object0);

If you are not interested in all the submaps, but looking for a specific value, then do this instead:

Map<String, Object> subMapForObject1 = 
    map.entrySet()
       .stream()
       .filter(e -> object1.equals(e.getValue());
       .collect(toMap(Map.Entry::getKey, Map.Entry::getValue)));

Upvotes: 2

Related Questions