Agrupando e criando uma lista com chaves duplicadas em Java [duplicado]
Estou tentando converter List<Integer[]>para Map<Integer, List<Integer>>.
Portanto, isso List<Integer[]>tem chaves duplicadas para ver um exemplo abaixo:
List<Integer[]> list = Arrays.asList(
new Integer[] {1, 23},
new Integer[] {2, 45},
new Integer[] {3, 25},
new Integer[] {1, 45},
new Integer[] {2, 54}
);
O requisito é converter isso no mapa abaixo, onde agrupa pelo índice 0 e colocar todos os valores sob a chave duplicada novamente em uma sub-lista. Então, finalmente, seria algo assim:
{1=[23, 45], 2=[45, 54], 3=[25]}
Atualmente, estou fazendo isso sem fluxos como abaixo. E não tenho certeza de como isso pode ser alcançado com o stream.
if (finalMap.containsKey(Integer.valueOf(dataList[0]))){
List<Integer> currentList = finalMap.get(Integer.valueOf(dataList[0]));
currentList.add(new Integer(Integer.valueOf(dataList[1])));
List<Integer> newList = new ArrayList<>(currentList);
finalMap.put(Integer.valueOf(dataList[0]), newList);
} else {
finalMap.put(
Integer.valueOf(dataList[0]),
new ArrayList<>(Arrays.asList(Integer.parseInt(dataList[1]))));
}
Respostas
Você pode fazer isso usando Collectors.groupingByo primeiro elemento da matriz e usar um coletor de mapeamento como um downstream para obter os valores adicionais. Finalmente, o downstream mais adiante Collectors.toListenvolve os valores. Use AbstractMap.SimpleEntrypara uma melhor manipulação com os itens da matriz.
Agora, a solução depende apenas se cada um Integer[]contém exatamente 2 itens ou 2+ itens :
Exatamente 2 itens em cada matriz
Cada um Integer[]sempre contém exatamente dois itens (por exemplo new Integer[] {1, 23}). Use Collectors.mappingpara obter o resultado array[1](valor da entrada) no List.
Map<Integer, List<Integer>> map = list.stream()
.map(array -> new AbstractMap.SimpleEntry<>(array[0], array[1]))
.collect(Collectors.groupingBy(
AbstractMap.SimpleEntry::getKey,
Collectors.mapping(AbstractMap.SimpleEntry::getValue, Collectors.toList())));
Na verdade, o SimpleEntryuso pode ser omitido e todo o fluxo simplificado se você abordar os arrays diretamente:
Map<Integer, List<Integer>> map = list.stream()
.collect(Collectors.groupingBy(
array -> array[0],
Collectors.mapping(array -> array[1], Collectors.toList())));
2+ itens em cada matriz
Cada um Integer[]pode conter dois ou mais itens (por exemplo new Integer[] {1, 23, 24}). Use Collectors.flatMappingpara obter os array[1].. array[n]itens (valor da entrada) no List. Lembre-se de que você precisa dividir a matriz primeiro para executar o agrupamento correto, portanto, o primeiro elemento array[0]é a chave e array[1] .. array[n]os valores - é por isso que o mapeamento plano é necessário.
Map<Integer, List<Integer>> map = list.stream()
.map(array -> new AbstractMap.SimpleEntry<>(
array[0],
Arrays.copyOfRange(array, 1, array.length)))
.collect(Collectors.groupingBy(
AbstractMap.SimpleEntry::getKey,
Collectors.flatMapping(
i -> Arrays.stream(i.getValue()),
Collectors.toList())));
Novamente, todo o fluxo pode ser simplificado omitindo o SimpleEntrywrapper:
Map<Integer, List<Integer>> map = list.stream()
.collect(Collectors.groupingBy(
array -> array[0],
Collectors.flatMapping(
array -> Arrays.stream(Arrays.copyOfRange(array, 1, array.length)),
Collectors.toList())));
Consequentemente, graças a obter um subarray que pode resultar em um array vazio, essa solução também funciona quando há pelo menos um elemento presente no Integer[]array. Um resultado com a matriz new Integer[] {3}na entrada seria:
{1=[23, 45], 2=[45, 54, 88], 3=[]}
Com Streams:
Map<Integer, List<Integer>> map =
dataList.stream().collect(Collectors.toMap(i -> i[0], i -> List.of(i[1]), (a, b) -> {
List<Integer> merged = new ArrayList<>(a);
merged.addAll(b);
return merged;
}));
Para facilitar a leitura, eu recomendaria que a operação de mesclagem fosse movida para um método separado. Você também pode tentar obter o mesmo resultado com, groupingBymas é um pouco mais complicado acertar ao usar matrizes.
Aqui está a solução sem usar nenhuma API de terceiros e usar fluxos.
Integer [] array1 = {1, 23};
Integer [] array2 = {2, 45};
Integer [] array3 = {3, 25};
Integer [] array4 = {1, 45};
Integer [] array5 = {2, 54};
List<Integer[]> intlist = Arrays.asList( array1,array2,array3,array4,array5);
Map<Integer, List<Integer>> grouped = intlist.stream()
.collect(Collectors.groupingBy(arr -> arr[0],
Collectors.mapping(arr -> arr[1], Collectors.toList())));
System.out.println( grouped );
Vai produzir
{1 = [23, 45], 2 = [45, 54], 3 = [25]}
como requerido.