I have a map Map<K, V>
and my goal is to remove the duplicated values and output the very same structure Map<K, V>
again. In case the duplicated value is found, there must be selected one key (k
) from the two keys (k1
and k2
) which hold these values, for this reason, assume the BinaryOperator<K>
giving k
from k1
and k2
is available.
Example input and output:
// Input
Map<Integer, String> map = new HashMap<>();
map.put(1, "apple");
map.put(5, "apple");
map.put(4, "orange");
map.put(3, "apple");
map.put(2, "orange");
// Output: {5=apple, 4=orange} // the key is the largest possible
My attempt using Stream::collect(Supplier, BiConsumer, BiConsumer)
is a bit very clumsy and contains mutable operations such as Map::put
and Map::remove
which I would like to avoid:
// // the key is the largest integer possible (following the example above)
final BinaryOperator<K> reducingKeysBinaryOperator = (k1, k2) -> k1 > k2 ? k1 : k2;
Map<K, V> distinctValuesMap = map.entrySet().stream().collect(
HashMap::new, // A new map to return (supplier)
(map, entry) -> { // Accumulator
final K key = entry.getKey();
final V value = entry.getValue();
final Entry<K, V> editedEntry = Optional.of(map) // New edited Value
.filter(HashMap::isEmpty)
.map(m -> new SimpleEntry<>(key, value)) // If a first entry, use it
.orElseGet(() -> map.entrySet() // otherwise check for a duplicate
.stream()
.filter(e -> value.equals(e.getValue()))
.findFirst()
.map(e -> new SimpleEntry<>( // .. if found, replace
reducingKeysBinaryOperator.apply(e.getKey(), key),
map.remove(e.getKey())))
.orElse(new SimpleEntry<>(key, value))); // .. or else leave
map.put(editedEntry.getKey(), editedEntry.getValue()); // put it to the map
},
(m1, m2) -> {} // Combiner
);
Is there a solution using an appropriate combination of Collectors
within one Stream::collect
call (e.g. without mutable operations)?
You can use Collectors.toMap
private Map<Integer, String> deduplicateValues(Map<Integer, String> map) {
Map<String, Integer> inverse = map.entrySet().stream().collect(toMap(
Map.Entry::getValue,
Map.Entry::getKey,
Math::max) // take the highest key on duplicate values
);
return inverse.entrySet().stream().collect(toMap(Map.Entry::getValue, Map.Entry::getKey));
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With