使用 Java Map 聚合 List 中重复元素的数值

使用 Java Map 聚合 List 中重复元素的数值

本文介绍了如何使用 Java map 结构有效地聚合 List 中具有相同类型(Type)的元素的数值,例如金额(Amount)和数量(Quantity)。通过将 List 转换为 Map,并利用 compute 方法或 Stream API 的 toMap 操作,可以避免手动循环和比较,从而简化代码并提高效率。本教程提供了详细的代码示例,展示了如何创建、更新和合并 Map 中的数据,最终得到聚合后的结果。

在处理包含重复元素的 List 时,如果需要对特定字段进行聚合操作,使用 Map 是一种非常有效的方法。Map 允许我们以键值对的形式存储数据,其中键是唯一的,这使得我们可以方便地根据键(例如,元素的类型)来累加相关的值(例如,金额和数量)。

使用 Map 的 compute 方法

如果已经有一个 Map,并且需要向其中添加或更新元素,可以使用 compute 方法。该方法接受一个键和一个 Bifunction 作为参数。BiFunction 接受键和当前值(如果存在)作为输入,并返回新的值。如果键不存在,则当前值为 NULL

以下示例展示了如何使用 compute 方法向 Map 中添加元素,并累加金额和数量:

立即学习Java免费学习笔记(深入)”;

import java.util.HashMap; import java.util.Map;  record Datav2(Double amount, Integer quantity) {}  public class AccumulateValues {      public static void main(String[] args) {         var map = new HashMap<>(Map.of("A", new Datav2(2.0, 3)));          // add element to map equivalent to Data("A", 3.0, 3)         map.compute("A", (k, v) -> {             if (v == null) {                 v = new Datav2(0.0, 0);             }             return new Datav2(3.0, v.quantity() + 3); // Corrected: Use 3.0 instead of v.amount = 3.0         });          System.out.println(map); // Output: {A=Datav2[amount=3.0, quantity=6]}     } }

注意事项:

  • compute 方法中的 BiFunction 必须返回新的值,而不是直接修改当前值。
  • 如果键不存在,BiFunction 应该返回一个新创建的对象
  • 上述代码已经修正,直接返回新的 Datav2 对象,避免了直接修改 v.amount 的问题。

使用 Stream API 的 toMap 方法

如果需要将一个 List 转换为 Map,可以使用 Stream API 的 toMap 方法。该方法接受三个参数:

  1. keyMapper: 用于生成键的 Function。
  2. valueMapper: 用于生成值的 Function。
  3. mergeFunction: 用于合并具有相同键的两个值的 BinaryOperator。

以下示例展示了如何使用 toMap 方法将 List 转换为 Map,并累加金额和数量:

import java.util.List; import java.util.stream.Collectors;  record Data(String type, Double amount, Integer quantity) {}  public class AccumulateValuesFromList {      public static void main(String[] args) {         var list = List.of(new Data("A", 2.0, 3),                 new Data("A", 3.0, 3),                 new Data("C", 2.0, 1),                 new Data("B", 10.0, 3),                 new Data("B", 2.0, 5));          var collected = list                 .stream()                 .collect(Collectors.toMap(                         // what will the key be                         Data::type,                         // what will the value be                         data -> new Datav2(data.amount, data.quantity),                         // how do we combine two values if they have the same key                         (d1, d2) -> new Datav2(d1.amount() + d2.amount(), d1.quantity() + d2.quantity())                 ));         System.out.println(collected); // Output: {A=Datav2[amount=5.0, quantity=6], B=Datav2[amount=12.0, quantity=8], C=Datav2[amount=2.0, quantity=1]}     } }

注意事项:

  • keyMapper 必须返回唯一的键。如果存在重复的键,则会抛出 IllegalStateException 异常。可以使用 mergeFunction 来处理重复的键。
  • mergeFunction 必须返回合并后的值。

总结

使用 Map 可以有效地聚合 List 中重复元素的数值。compute 方法适用于向已有的 Map 中添加或更新元素,而 toMap 方法适用于将 List 转换为 Map。选择哪种方法取决于具体的需求和场景。通过合理使用 Map,可以简化代码并提高效率。

© 版权声明
THE END
喜欢就支持一下吧
点赞7 分享