Eu sei como "transformar" um Java simples List
de Y
-> Z
, ou seja:
List<String> x;
List<Integer> y = x.stream()
.map(s -> Integer.parseInt(s))
.collect(Collectors.toList());
Agora eu gostaria de fazer basicamente o mesmo com um mapa, ou seja:
INPUT:
{
"key1" -> "41", // "41" and "42"
"key2" -> "42 // are Strings
}
OUTPUT:
{
"key1" -> 41, // 41 and 42
"key2" -> 42 // are Integers
}
A solução não deve ser limitada a String
-> Integer
. Assim como no List
exemplo acima, eu gostaria de chamar qualquer método (ou construtor).
java
mapreduce
java-8
java-stream
collectors
Benjamin M
fonte
fonte
e -> e.getKey()
porMap.Entry::getKey
. Mas isso é uma questão de gosto / estilo de programação.Aqui estão algumas variações da resposta de Sotirios Delimanolis , que foi muito boa para começar (+1). Considere o seguinte:
Alguns pontos aqui. Primeiro é o uso de curingas nos genéricos; isso torna a função um pouco mais flexível. Um curinga seria necessário se, por exemplo, você desejasse que o mapa de saída tivesse uma chave que seja uma superclasse da chave do mapa de entrada:
(Também há um exemplo para os valores do mapa, mas é realmente artificial, e admito que ter o curinga limitado para Y ajuda apenas em casos extremos.)
Um segundo ponto é que, em vez de executar o fluxo sobre o mapa de entrada
entrySet
, eu o executei nokeySet
. Isso torna o código um pouco mais limpo, eu acho, ao custo de ter que buscar valores fora do mapa, e não na entrada do mapa. Aliás, eu inicialmente tivekey -> key
como o primeiro argumentotoMap()
e isso falhou com um erro de inferência de tipo por algum motivo. Mudando para(X key) -> key
funcionou, assim comoFunction.identity()
.Ainda outra variação é a seguinte:
Isso usa em
Map.forEach()
vez de fluxos. Isso é ainda mais simples, eu acho, porque dispensa os colecionadores, que são um pouco desajeitados para usar nos mapas. O motivo é queMap.forEach()
fornece a chave e o valor como parâmetros separados, enquanto o fluxo possui apenas um valor - e você deve escolher se deseja usar a chave ou a entrada do mapa como esse valor. No lado negativo, falta a bondade rica e fluida das outras abordagens. :-)fonte
Function.identity()
pode parecer legal, mas como a primeira solução exige uma pesquisa de mapa / hash para todas as entradas, enquanto todas as outras soluções não, eu não recomendaria.Uma solução genérica como essa
Exemplo
fonte
A função do Guava
Maps.transformValues
é o que você está procurando e funciona bem com expressões lambda:fonte
java.util.Function
, você tem duas opções. 1. Evite o problema usando um lambda para permitir que a inferência de tipo Java descubra. 2. Use uma referência de método como javaFunction :: apply para produzir um novo lambda que a inferência de tipo possa descobrir.É absolutamente necessário que seja 100% funcional e fluente? Caso contrário, que tal isso, que é o mais curto possível:
( se você pode viver com a vergonha e a culpa de combinar fluxos com efeitos colaterais )
fonte
Minha biblioteca StreamEx , que aprimora a API de fluxo padrão, fornece uma
EntryStream
classe que melhor se adapta à transformação de mapas:fonte
Uma alternativa que sempre existe para fins de aprendizado é criar seu coletor personalizado por meio de Collector.of (), embora o coletor toMap () JDK aqui seja sucinto (+1 aqui ).
fonte
map2.entrySet().forEach(entry -> { if (map1.containsKey(entry.getKey())) { map1.get(entry.getKey()).merge(entry.getValue()); } else { map1.put(entry.getKey(),entry.getValue()); } }); return map1
ou valores serão perdidos ao reduzir.Se você não se importa em usar bibliotecas de terceiros, minha lib cyclops- react possui extensões para todos os tipos de coleções do JDK , incluindo o Map . Podemos apenas transformar o mapa diretamente usando o operador 'map' (por padrão, o mapa atua sobre os valores no mapa).
O bimap pode ser usado para transformar as chaves e os valores ao mesmo tempo
fonte
A solução declarativa e mais simples seria:
yourMutableMap.replaceAll ((key, val) -> return_value_of_bi_your_function); Nb. esteja ciente de que está modificando o estado do seu mapa. Portanto, isso pode não ser o que você deseja.
Felicidades para: http://www.deadcoderising.com/2017-02-14-java-8-declarative-ways-of-modifying-a-map-using-compute-merge-and-replace/
fonte