【问题标题】:Java8 transform a [List<Object>, String] in a Map<Object, String>Java8 在 Map<Object, String> 中转换 [List<Object>, String]
【发布时间】:2017-01-13 17:10:25
【问题描述】:

我有一个List&lt;Computer&gt;。每台计算机都有一个 CPU 列表和一个主机名。 所以,假设我有:

List<Computer> computers

我可以打电话

List<CPU> CPUs = computer.getCPUs();

我可以打电话

String hostname = computer.getHostName();

我想要做的是,使用 Streams,获取一个 Map,其中包含作为键的 CPU 和作为字符串的主机名。同一台计算机中的同一 CPU 将复制主机名。

我该怎么做?

Java8 之前的代码是这样的:

public Map<CPU, String> getMapping(List<Computer> computers) {
    Map<CPU, String> result = new HashMap<>();
    for (Computer computer : computers) {
        for (CPU cpu : computer.getCPUs()) {
            result.put(cpu, computer.getHostname());
        }
    }

    return result;
}

【问题讨论】:

  • computercomputers是什么关系。如果您希望您的问题能够继续存在,请添加完成您的任务的 Java 8 之前的代码。
  • 谢谢,我添加了 pre Java8 代码
  • 我认为没有比您已有的更好的流和 lambdas 解决方案
  • 如果同一个 CPU 链接到两个以上的主机名会发生什么?

标签: java java-8 java-stream


【解决方案1】:

如果你的CPU 类有一个对它的Computer 实例的反向引用,那么你可以很容易地做到这一点。首先在所有计算机上进行流式传输,并使用getCPUs 进行平面映射,这将为您提供所有 CPU 的Stream&lt;CPU&gt;。然后您可以使用Collectors.toMap 收集到Map&lt;CPU, String&gt; 中,使用Function.identity 作为键,并使用lambda 首先提取Computer,然后从CPU 中提取主机名作为值。 在代码中:

computers.stream()
    .flatMap(computer -> computer.getCPUs().stream())
    .collect(Collectors.toMap(Function.identity(), cpu -> cpu.getComputer().getHostname()));

【讨论】:

  • 是什么让你假设存在cpu.getComputer() 方法?
  • 正如我在第一句话中解释的那样,我假设这是因为这是一个合理的假设,并且有必要使用 Stream API 干净地解决这个问题。如果不存在这样的方法,流管道将变得更加低效,因为我认为如果没有中间收集步骤就无法做到。
【解决方案2】:

您可以通过实现自己的Collector 来为同一台计算机的所有 CPU 分配相同的值:

Map<CPU, String> cpus = computers.stream().collect(
    Collector.of(
        HashMap::new,
        // Put each cpu of the same computer using the computer's hostname as value
        (map, computer) -> computer.getCPUs().stream().forEach(
            cpu -> map.put(cpu, computer.getHostName())
        ),
        (map1, map2) -> { map1.putAll(map2); return map1; }
    )
);

这基本上等同于您当前使用Stream API 所做的事情,唯一的区别是您可以通过简单地使用并行流而不是普通流来并行化它,但在这种特殊情况下作为任务很小,在性能方面可能没有太大帮助,因此在这种情况下使用Stream API 可能会被视为有点滥用。

【讨论】:

    【解决方案3】:

    您可以使用中间Entry 将 CPU 和主机名放在一起:

    Map<CPU, String> map = computers.stream()
            .flatMap(c -> c.getCPUs().stream().map(cpu -> new AbstractMap.SimpleEntry<>(cpu, c.getHostName())))
            .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-11-21
      • 2018-09-22
      • 1970-01-01
      • 1970-01-01
      • 2018-11-23
      • 1970-01-01
      相关资源
      最近更新 更多