【问题标题】:Using Java 8 Streams' Collectors to increment value based of existing key/value pair使用 Java 8 Streams 的收集器根据现有的键/值对增加值
【发布时间】:2019-10-29 07:15:18
【问题描述】:

假设有一个List<Object> 并且Object 包含两个方法:getUserIdgetPoints

考虑List<Object> 包含三个对象,它们包含以下数据:

userId A; 3 points
userId A; 5 points
userId B; 1 point

正确收集此信息后,我希望有一个看起来像这样的Map<String, Integer>

A: 8,
B: 1

我正在尝试使用 Java 的 8 个功能接口,即流,因为我只需要最终结果,而我没有也不需要任何这些映射之间的映射。如果没有其他办法,我愿意修改它。 我首先想到了这个:

this.service.getListObject()
    .stream()
    .collect(Collectors.toMap(Object::getUserId, Object::getPoints));

但是,这显示不够,因为它总是用最新的值替换键,从而产生:

A: 5,
B: 1

如何调整Collectors.toMap() 的最后一位,以根据地图中已存储的值自动增加其值,从而产生上述结果?

【问题讨论】:

  • 其实Collectors.toMap会在key不唯一的情况下抛出异常;它不会用最新的值替换它。
  • 我不认为这发生在我最后一次执行程序的尝试中。最终,它没有正确更新值,但没有抛出异常,我保证有重复的键。
  • 也许,您确实指定了像 (a,b)->b 这样的合并函数而不是省略它?

标签: java java-8 functional-programming java-stream


【解决方案1】:

Collectors.groupingByCollectors.summingInt 一起用作下游收集器:

this.service.getListObject()
    .stream().collect(Collectors.groupingBy(
        Object::getUserId, Collectors.summingInt(Object::getPoints)));

【讨论】:

    【解决方案2】:

    为了更正你开始的实现,你需要一个合并函数:

    ...stream().collect(Collectors.toMap(CustomObject::getUserId, 
                        CustomObject::getPoints, Integer::sum)); // <--- summing value here
    

    最终也可以用groupingBysummingInt 的组合来表示。

    【讨论】:

      猜你喜欢
      • 2015-06-19
      • 1970-01-01
      • 1970-01-01
      • 2014-04-29
      • 1970-01-01
      • 2018-03-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多