如果 java 中的第一个索引值相同,则合并列表中列表的索引

merge indexes of lists in a list if first index value is same in java

如果 Java 8 中的第一个索引匹配,我希望将列表合并到列表中。 我有一个列表

[[ABC, 1.0, 4.0, 4.0], [ABC, 2.0, 4.0, 4.0], [ABC, 1.0, 72.0, 72.0], [XYZ, 1.0, 36.0, 36.0], [XYZ, 2.0, 16.0, 16.0]]

而且我希望以一种有效的方式得到如下结果,就像在 java 中使用流一样。 结果应该是

[[ABC, 4.0, 116.0, 116.0], [XYZ, 3.0, 52.0, 52.0]]

有人可以帮忙吗?

在这种情况下,Collectors.toMap 应与选择的键一起使用作为第一个索引,并使用合并函数对其余元素求和。

示例:

List<List<Object>> input = Arrays.asList(
    Arrays.asList("ABC", 1.0,  4.0,  4.0),
    Arrays.asList("ABC", 2.0, 40.0, 40.0),
    Arrays.asList("ABC", 1.0, 72.0, 72.0),
    Arrays.asList("XYZ", 1.0, 36.0, 36.0),
    Arrays.asList("XYZ", 2.0, 16.0, 16.0)
); 

List<List<Object>> merged = new ArrayList<>(input.stream()
    .collect(Collectors.toMap(
        list -> list.get(0),
        list -> list,
        (l1, l2) -> Stream.concat(
                Stream.of(l1.get(0)),
                IntStream.range(1, l1.size())
                    .mapToObj(i -> (Double)l1.get(i) + (Double)l2.get(i))
            )
            .collect(Collectors.toList()),
        LinkedHashMap::new  // keep insertion order
    ))
    .values() // Collection<List<Object>>
);

System.out.println(merged);
// -> [[ABC, 4.0, 116.0, 116.0], [XYZ, 3.0, 52.0, 52.0]]

但是,输入列表似乎是字符串和双精度数据的混合,它们应该更好地转换为具有适当 merge 函数的 class/record。

这里是使用 record 的示例,自 Java 16 以来可用 merge 方法和覆盖的 toString 方法。

record Item(String name, double ... values) {
    Item merge(Item that) {
        return new Item(
            this.name, 
            IntStream.range(0, this.values.length)
                .mapToDouble(i -> this.values[i] + that.values[i])
                .toArray()
        );
    }
    
    @Override
    public String toString() {
        return String.format("[%s, %s]", name, 
            Arrays.stream(values)
                .mapToObj(String::valueOf)
                .collect(Collectors.joining(", "))
        );
    }
};

List<Item> data = Arrays.asList(
    new Item("ABC", 1.0,  4.0,  4.0),
    new Item("ABC", 2.0, 40.0, 40.0),
    new Item("ABC", 1.0, 72.0, 72.0),
    new Item("XYZ", 1.0, 36.0, 36.0),
    new Item("XYZ", 2.0, 16.0, 16.0)
); 
List<Item> items = data.stream()
    .collect(Collectors.collectingAndThen(
        Collectors.toMap(
            Item::name,
            item -> item,
            Item::merge,
            LinkedHashMap::new  // keep insertion order
        ), 
        map -> new ArrayList<>(map.values())
    ));

System.out.println(items);
// -> [[ABC, 4.0, 116.0, 116.0], [XYZ, 3.0, 52.0, 52.0]]
  1. 对于列表列表中的每个列表
  2. 如果第一个值不在哈希图中,使用第一个值作为键添加到哈希图中
  3. 如果键已经在 hashmap 中,则与 hashmap 中已有的列表合并
  4. 根据 hashmap 条目集创建新的列表列表

额外功劳:使用 LinkedHashMap 保留外观顺序,如果您希望按字母顺序排列,则使用 TreeMap