【问题标题】:How make multiple aggregation on list of HashMaps with java 8如何使用 java 8 在 HashMaps 列表上进行多重聚合
【发布时间】:2018-10-15 10:03:22
【问题描述】:

我对 java 8 实现有关 HashMap 列表的多重聚合有疑问,(首选 "reduce" 函数,但不是必须的)

我需要按键名进行多重聚合 - "service" with split("_")[0] 如下面的 Json:

假设我的数据结构:

 List<Map<String, Object>> payments = new ArrayList<>();
  for(int i=0 ; ....i++){
      Map<String, String> map = new HashMap<>();
      map.put("service","IMAP_"+i);
      map.put("storageValue",<some value>)
      ....
      payments.add(map);
  }

Json:

{
  "payments": [
    {
      "service": "IMAP_1",
      "storageValue": 10,
      "users": "10"
    },
    {
      "service": IMAP_2,
      "storageValue": 20,
      "users": "1"
    },
    {
      "storageValue": 200,
      "service": "Office 365 Exchange_1",
      "users": "15"
    },
    {
      "storageValue": 200,
      "service": "Office 365 Exchange_2",
      "users": "10"
    },
    {
      "storageValue": 50,
      "service": "SalesForce_1",
      "users": "100"
    }
  ]
}

结果应该是:

{
      "payments": [
        {
          "service": "IMAP",
          "storageValue": 30,
          "users": "11"
        },
        {
          "storageValue": 400,
          "service": "Office 365 Exchange",
          "users": "25"
        },
        {
          "storageValue": 50,
          "service": "SalesForce",
          "users": "100"
        }
      ]
    }

应该是什么..

payments.stream().forEach(paymet -> {
                paymet.entrySet().stream().map(....?...).reduce()...
            );

【问题讨论】:

  • 把它变成一个对象{ "service": "IMAP", "storageValue": "30", "users": "11" },会让你的生活轻松很多。
  • @nullpointer 你是对的,但它是无法更改的遗留代码
  • @VitalyT 当然可以更改。即使您的职责只涉及这个单一操作,您最好先将这些映射转换为有意义的类的实例,使用这些实例以可维护的方式执行操作,然后将生成的实例转换回映射。但我怀疑这是您可以更改的代码的唯一部分。目前,您将要创建更多“无法更改的遗留代码”。

标签: java java-8


【解决方案1】:

这是一个不完整的建议,将Collectors.groupingByCollectors.reducing 结合在一起。

Map<String,Optional<Map<String,Object>>> result = 
    payments.stream ().collect(Collectors.groupingBy (map -> map.get ("service").split ("_")[0],
                               Collectors.reducing ((m1,m2)-> {
                                   Map<String,String> m = new HashMap<>();
                                   m.put("service",m1.get("service")); // you may have to remove the _1 suffix
                                   m.put("storageValue",(Integer)m1.get("storageValue")+(Integer)m2.get("storageValue"));
                                   m.put("users",(Integer)m1.get("users")+(Integer)m2.get("users"));
                                   return m;
                               })));

请注意,由于您的 Maps 包含 String 值,因此将这些 Map 的值添加为数字有点不方便。您必须进行一些从 Stringint 的转换,反之亦然。

将每个Map 转换为具有存储、用户和存储值属性的某个类的实例可能会有所帮助。然后你可以有一个结合两个这样的实例的方法。

【讨论】:

  • @Eran 假设它是一个整数......我只需要自己进行 sum 实现吗?我可以改用Java8 sum 实现吗?谢谢:)
  • @VitalyT 假设什么是整数?你的地图的价值?在这种情况下,它必须是 Map&lt;String,Object&gt;,并且您需要将值转换为 Integer 才能执行加法。
  • 你说得对,换成 Object ...能不能用 sum 函数改一下答案...
  • @VitalyT 查看编辑。我没有测试,所以可能有一些错别字。
  • 非常感谢,但我想知道我是否可以在 java8 函数中使用“sum”构建?
【解决方案2】:

试试这个。这不是优雅:)。

首先将service键的值更改为新值

 payments.stream()
            .forEach(item -> item.put("service", item.get("service").split("_")[0]));

然后

HashMap<String, HashMap> mapOfMaps = payments.stream()
            .collect(Collectors.toMap(hashMap -> hashMap.get("service"),
                    hashMap -> (HashMap) hashMap,
                    YOURCLASS::merge, HashMap::new));
List<HashMap> result = new ArrayList<>(mapOfMaps.values());

并定义一个方法来合并两个映射,如下所示:

private static HashMap<String, String> merge(HashMap<String, String> map1, HashMap<String, String> map2) {
    if (map1.get("service").equals(map2.get("service"))) {
        Long storageValue = Long.valueOf(map1.get("storageValue")) + Long.valueOf(map2.get("storageValue"));
        map1.put("storageValue", storageValue.toString());
        Long users = Long.valueOf(map1.get("users")) + Long.valueOf(map2.get("users"));
        map1.put("users", users.toString());
    }
    return map1;
}

【讨论】:

    猜你喜欢
    • 2021-06-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-06-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多