在java中分组和创建具有重复键的列表

qlvxas9a  于 2021-07-08  发布在  Java
关注(0)|答案(3)|浏览(428)

这个问题在这里已经有答案了

java 8将列表转换为查找Map(9个答案)
坚持lambda表达式和Map(3个答案)
Java8流收集器-用于创建多个bucket中包含对象的Map的收集器(2个答案)
上个月关门了。
我在试着改变 List<Integer[]>Map<Integer, List<Integer>> .
所以这个 List<Integer[]> 有重复的键示例如下:

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}
);

要求是将此转换为按第0个索引分组的下图,并将重复键下的所有值再次放入子列表。最后是这样的:

{1=[23, 45], 2=[45, 54], 3=[25]}

我目前正在做这个没有流如下。我也不知道如何用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]))));
}
czfnxgou

czfnxgou1#

您可以使用 Collectors.groupingBy 通过数组的第一个元素,并使用Map收集器作为下游来获取进一步的值。最后,进一步的下游 Collectors.toList Package 值。使用 AbstractMap.SimpleEntry 以便更好地处理数组项。
现在,解决方案只取决于 Integer[] 正好包含2项或2+项:

每个数组中正好有2个项目

每个 Integer[] 始终包含两个项目(例如。 new Integer[] {1, 23} ). 使用 Collectors.mapping 为了得到 array[1] (输入值)结果到 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())));

事实上 SimpleEntry 如果直接寻址数组,则可以省略用法并简化整个流:

Map<Integer, List<Integer>> map = list.stream()
    .collect(Collectors.groupingBy(
            array -> array[0],
            Collectors.mapping(array -> array[1], Collectors.toList())));

每个阵列中有2+个项目

每个 Integer[] 可以包含两个或多个项目(例如。 new Integer[] {1, 23, 24} ). 使用 Collectors.flatMapping 为了得到 array[1] .. array[n] 项目(条目的值) List . 请记住,您需要首先拆分数组以执行正确的分组,因此第一个元素 array[0] 是关键 array[1] .. array[n] 是值-这就是为什么需要flatmapping。

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())));

同样,可以简化整个流,省略 SimpleEntry Package 器:

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())));

因此,由于得到了一个可能导致空数组的子数组,当数组中至少存在一个元素时,该解决方案也可以工作 Integer[] 数组。数组的结果 new Integer[] {3} 在输入中: {1=[23, 45], 2=[45, 54, 88], 3=[]}

4urapxun

4urapxun2#

以下是不使用任何第三方api和流的解决方案。

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 );

将产生
{1=[23, 45], 2=[45, 54], 3=[25]}
按要求。

3qpi33ja

3qpi33ja3#

对于流:

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;
        }));

为了可读性,我建议将合并操作移到一个单独的方法。你也可以试着用 groupingBy 但在使用数组时,要正确处理这个问题就有点困难了。

相关问题