Java8如何将[List<Object>, String]转换为Map<Object, String>?

3

我有一个 List<Computer>。每台计算机都有一个CPU列表和一个主机名。

假设我有:

List<Computer> computers

我可以调用。
List<CPU> CPUs = computer.getCPUs();

而且我可以调用

String hostname = computer.getHostName();

我希望通过使用流,获得一个包含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;
}

3
computercomputers 之间的关系是什么?如果您希望您的问题得到回答,请添加一些使用 pre-Java 8 代码来完成您的任务。 “computer” 表示单个计算机,而“computers” 表示多台计算机。 以下是一个 pre-Java 8 的代码示例,用于将字符串数组转换为大写形式:String[] words = {"computer", "programming", "language"}; for (int i = 0; i < words.length; i++) { words[i] = words[i].toUpperCase(); } - PM 77-1
谢谢,我添加了Java8之前的代码。 - Andrea Giuliano
1
我认为没有比你已经拥有的流和lambda解决方案更好的了。 - fps
如果同一CPU连接到两个以上的主机名,会发生什么? - LHA
3个回答

1
如果您的CPU类有对其Computer实例的反向引用,那么您可以轻松地完成此操作。首先流式处理所有计算机,并使用getCPUs进行平面映射,这将为您提供所有CPU的Stream<CPU>。然后,您可以使用Collectors.toMap将其收集到Map<CPU,String>中,其中使用Function.identity作为键,使用lambda从CPU中提取首先是Computer,然后是主机名作为值。
代码如下:
computers.stream()
    .flatMap(computer -> computer.getCPUs().stream())
    .collect(Collectors.toMap(Function.identity(), cpu -> cpu.getComputer().getHostname()));

2
你是怎么得出假设存在 cpu.getComputer() 方法的? - Holger
正如我在第一句中所解释的那样,我做出了这个假设,因为这是一个合理的假设,并且对于使用Stream API来解决问题而言是必要的。如果不存在这样的方法,那么流水线将变得更加低效,因为我认为你无法在没有中间收集步骤的情况下完成它。 - diesieben07

1
你可以通过实现自己的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在性能方面可能没有太大帮助,因此在这种情况下使用Stream API可能被视为有点滥用。


1
你可以使用一个中间的 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));

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接