A straightforward solution would be:
- Build a temporary inverted map
Map<Object, List<Integer>>
- Filter the inverted map to keep only duplicates
- 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}