Eu tenho um mapa Map<K, V>
e meu objetivo é remover os valores duplicados e gerar a mesma estrutura Map<K, V>
novamente. Caso o valor duplicado for encontrado, deve ser selecionada uma chave ( k
) das duas teclas ( k1
e k1
) que detêm esses valores, por isso, assumir a BinaryOperator<K>
dar k
a partir k1
e k2
está disponível.
Exemplo de entrada e saída:
// 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
Minha tentativa de usar Stream::collect(Supplier, BiConsumer, BiConsumer)
é um pouco desajeitada e contém operações mutáveis como Map::put
e Map::remove
que eu gostaria de evitar:
// // 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
);
Existe uma solução usando uma combinação apropriada de Collectors
dentro de uma Stream::collect
chamada (por exemplo, sem operações mutáveis)?
java
dictionary
java-8
java-stream
collectors
Nikolas
fonte
fonte
Stream
s?Map::put
ouMap::remove
dentro doCollector
.BiMap
. Possivelmente uma duplicata de Remover valores duplicados do HashMap em JavaRespostas:
Você pode usar Collectors.toMap
fonte
Tente o seguinte: A maneira simples é inversa à chave e ao valor e use o
toMap()
coletor com a função de mesclagem.fonte
map
operação intermediária compra. Você parece trocar chaves e valores, isso é claro, mas qual é o objetivo? Você poderia fazer isso na etapa de coleta da mesma forma?swap(); collect(key, value, binOp);
vez decollect(value, key, binOp)
. Talvez eu precise tentar isso em um jshell de verdade?Acho a solução sem fluxos mais expressiva:
Isso é usado
Map.merge
com a sua bi-função redutora e é usadoLinkedHashMap
para preservar a ordem das entradas originais.fonte
Encontrei uma maneira de usar apenas
Collectors
sem a necessidade de coletar e processar novamente o mapa retornado. A ideia é:Agrupe o
Map<K, V>
paraMap<V, List<K>
.Reduza as novas teclas (
List<K>
) paraK
usarBinaryOperator<K>
.Inverta
Map<V, K>
novamente aMap<K, V>
estrutura - o que é seguro, pois as chaves e os valores são garantidos como distintos.O código final:
fonte
Outra maneira de obter o resultado desejado com "Stream and Collectors.groupingBy".
fonte