【问题标题】:How to replace HashMap with LinkedhashMap with streams?如何用带流的 LinkedhashMap 替换 HashMap?
【发布时间】:2019-04-01 21:39:46
【问题描述】:

你能帮我整理一下我的Map吗?

我有以下结构,我想在 LinkedHashMap 的客户下按价值相反的顺序组装应用程序。

[{
  "CUSTOMER_1": {
    "APP_1": "1"
  },
  "CUSTOMER_2": {
    "APP_1": "2",
    "APP_3": "7",
    "APP_2": "3"
  }
}]

我已经有一个组合地图的 lambda:

 final Map<String, Map<String, Long>> organizationApps = taskHandles.stream().map(this::mapPayload)
            .flatMap(e -> e.entrySet().stream())
            .collect(groupingBy(Map.Entry::getKey, of(HashMap::new,
                    (r, t) -> t.getValue().forEach((k, v) -> r.merge(k, v, Long::sum)),
                    (r1, r2) -> {
                        r2.forEach((v1, v2) -> r1.merge(v1, v2, Long::sum));
                        return r1;
                    }))
            );

我现在需要的是用LinkedHashMap 替换HashMap 表示的organizationApps 值,并将这些值按正确的顺序放入LinkedHashMap

我如何在 lambda 中做到这一点?

更新:

我可以使用以下代码实现必要的输出:

    final Map<String, Map<String, Long>> organizationApps = taskHandles.stream().map(this::mapPayload)
            .flatMap(e -> e.entrySet().stream())
            .collect(groupingBy(Map.Entry::getKey, of(HashMap::new,
                    (r, t) -> t.getValue().forEach((k, v) -> r.merge(k, v, Long::sum)),
                    (r1, r2) -> {
                        r2.forEach((v1, v2) -> r1.merge(v1, v2, Long::sum));
                        return r1;
                    }))
            );

    organizationApps.forEach((key, value) -> {
        final Map<String, Long> sorted = value.entrySet()
                .stream()
                .sorted(reverseOrder(Map.Entry.comparingByValue()))
                .collect(toMap(Map.Entry::getKey, Map.Entry::getValue, (e1, e2) -> e2,
                        LinkedHashMap::new));
        organizationApps.put(key, sorted);
    });

我怎样才能在一个 lambda 中做到这一点?

【问题讨论】:

  • 这是一个相关问题:stackoverflow.com/questions/29721095/…。重要的是,您需要在收集之前对流进行适当的排序。
  • 嗨瑞恩!我想我需要在组装地图后对其进行排序,因为最初我可以有 2 个带有重复键的地图的列表,我通过对值求和来合并地图
  • 我有以下问题:为什么需要在一个 lambda 中执行此操作?即使这可能 - 你可能会有非常大而丑陋的代码和平。而且我已经很难理解你的代码中发生了什么。恕我直言 lambdas 并不总是此类问题的最佳解决方案。如here 所述 - lambdas 应该是一个表达式,而不是叙述。尽管语法简洁,但 lambda 应该准确地表达它们提供的功能。
  • 1) 因为我想看结果并与下面的结果进行比较 2) 我想获得更多关于 lambdas 的知识
  • 可能有一些不同的方式来组织操作,但最后你需要应用程序的合并/求和结果才能进行排序,所以我认为它总是需要(至少) 两个合乎逻辑的步骤。

标签: java lambda java-stream linkedhashmap collectors


【解决方案1】:

您无法避免将值收集到地图中,然后才能创建按结果值排序的LinkedHashMap,但您可以将转换步骤指定为自定义收集器的finisher函数:

Map<String, Map<String, Long>> organizationApps = input.stream()
    .flatMap(e -> e.entrySet().stream())
    .collect(groupingBy(Map.Entry::getKey, Collector.of(HashMap::new,
        (r, t) -> t.getValue().forEach((k, v) -> r.merge(k, v, Long::sum)),
        (r1, r2) -> {
            r2.forEach((v1, v2) -> r1.merge(v1, v2, Long::sum));
            return r1;
        },
        (Map<String, Long> m) -> m.entrySet().stream()
            .sorted(Collections.reverseOrder(Map.Entry.comparingByValue()))
            .collect(toMap(Map.Entry::getKey, Map.Entry::getValue, (e1, e2) -> e2,
                LinkedHashMap::new))
    )));

相当于以下 (Java 9+) 代码

Map<String, Map<String, Long>> organizationApps = input.stream()
    .flatMap(m -> m.entrySet().stream())
    .collect(groupingBy(Map.Entry::getKey, collectingAndThen(flatMapping(
            t -> t.getValue().entrySet().stream(),
            toMap(Map.Entry::getKey, Map.Entry::getValue, Long::sum)),
        (Map<String, Long> m) -> m.entrySet().stream()
            .sorted(Collections.reverseOrder(Map.Entry.comparingByValue()))
            .collect(toMap(Map.Entry::getKey, Map.Entry::getValue, (e1, e2) -> e2,
                LinkedHashMap::new))
    )));

this answer 的末尾是 flatMapping 收集器的 Java 8 兼容实现,但您的自定义收集器也可以完成这项工作。

【讨论】:

  • 谢谢,这正是我想要的!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-04-16
  • 2015-02-26
  • 2011-02-22
  • 1970-01-01
  • 2015-02-12
  • 2015-06-05
  • 2012-05-13
相关资源
最近更新 更多