前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >【译】Java 中将两个 List 映射成 Map 看这一篇就够了

【译】Java 中将两个 List 映射成 Map 看这一篇就够了

作者头像
明明如月学长
发布2023-05-04 08:43:34
1.3K0
发布2023-05-04 08:43:34
举报

1. 概述

在 Java 中,经常有两个需要关联的独立列表。换句话说,我们有两个列表,一个包含键,另一个包含值。然后,我们希望得到一个 Map,它将键列表中的每个元素与值列表中对应的元素关联起来。

在本教程中,我们将探讨如何以不同的方式实现这一目标。

2. 问题介绍

首先,让我们通过一个例子来了解问题。假设我们有两个列表:

代码语言:javascript
复制
final List<String> KEY_LIST = Arrays.asList("Number One", "Number Two", "Number Three", "Number Four", "Number Five");
final List<Integer> VALUE_LIST = Arrays.asList(1, 2, 3, 4, 5);

现在,我们想要将上述两个列表与一个 Map 关联起来。但是首先,让我们初始化一个包含预期键值对的 HashMap:

代码语言:javascript
复制
final Map<String, Integer> EXPECTED_MAP = new HashMap<String, Integer>() {{
    put("Number One", 1);
    put("Number Two", 2);
    put("Number Three", 3);
    put("Number Four", 4);
    put("Number Five", 5);
}};

正如上面的代码所示,将两个列表组合的规则非常简单。接下来,我们将看看如何实现这一点。

3. 关于验证的说明

现在我们理解了问题,可能已经意识到给定的两个列表必须包含相同数量的元素,比如 KEY_LIST 和 VALUE_LIST。然而,在实践中,由于我们无法预测所得到的数据质量,两个给定的列表可能具有不同的大小。 如果是这种情况,我们必须按要求执行进一步的操作。

通常,有两种选择:

  1. 抛出异常并中止关联操作。
  2. 报告不匹配的问题作为警告,并继续创建 Map 对象以仅包含匹配的元素。

我们可以使用简单的 if 语句来实现这一点:

代码语言:javascript
复制
int size = KEY_LIST.size();
if (KEY_LIST.size() != VALUE_LIST.size()) {
    // 抛出异常或打印警告,并获取较小的大小并继续:
    size = Math.min(KEY_LIST.size(), VALUE_LIST.size());
}

// 以 size 变量进行后续处理

为简单起见,我们将假设两个列表总是具有相同的大小,并在后续的代码示例中省略此验证。此外,我们将使用单元测试断言来验证方法是否返回了预期的结果。

4. 循环填充 Map

由于两个输入列表具有相同的大小,我们可以使用单个循环将两个列表关联起来。接下来,让我们看看如何做到这一点:

代码语言:javascript
复制
Map<String, Integer> result = new HashMap<>();

for (int i = 0; i < KEY_LIST.size(); i++) {
    result.put(KEY_LIST.get(i), VALUE_LIST.get(i));
}
assertEquals(EXPECTED_MAP, result);

正如上面的示例所示,我们创建了一个名为 result 的新 HashMap。然后,我们使用 for 循环迭代 KEY_LIST 中的每个元素,并对于每个元素,我们使用相同的索引 i 从 VALUE_LIST 中检索相应的元素。然后,put() 方法将键值对填充到 result map 中。

5. 使用 Stream API

Stream API 提供了许多简洁高效的方式来操作 Java 集合。因此,接下来,让我们使用 Java Stream API 将两个列表关联起来:

代码语言:javascript
复制
Map<String, Integer> result = IntStream.range(0, KEY_LIST.size())
  .boxed()
  .collect(Collectors.toMap(KEY_LIST::get, VALUE_LIST::get));
assertEquals(EXPECTED_MAP, result);

正如上面的代码所示,IntStream.range() 方法生成从 0 到 KEY_LIST 大小的整数流。值得注意的是,IntStream 是一个原始流。因此,我们使用 boxed() 方法将 IntStream 转换为 Stream,这使我们能够使用 collect() 方法将元素收集到一个 Map 中。

6. 使用 Iterator

我们已经学习了两种将两个列表关联起来并得到 Map 结果的方法。然而,如果我们更仔细地看这两种解决方案,我们会发现这两种方法都使用了 List#get() 方法。换句话说,我们调用 List.get(i) 通过索引访问元素,同时构建关联。这被称为随机访问。

如果我们的列表是 ArrayList,这可能是最常见的情况,那么数据由数组支持。因此,随机访问是快速的。

然而,如果我们得到的是两个大的 LinkedList,按索引访问元素可能会很慢。这是因为 LinkedList 需要从开头迭代列表到所需的索引。

因此,使用 Iterator 可以是一种更有效的遍历列表的方式,特别是对于大型列表:

代码语言:javascript
复制
Map<String, Integer> result = new HashMap<>();

Iterator<String> ik = KEY_LIST.iterator();
Iterator<Integer> iv = VALUE_LIST.iterator();
while (ik.hasNext() && iv.hasNext()) {
    result.put(ik.next(), iv.next());
}

assertEquals(EXPECTED_MAP, result);

在此示例中,我们创建了两个 Iterator 对象,一个用于每个列表。然后,我们使用 while 循环同时迭代两个列表,使用每个 Iterator 的 next() 方法检索列表中的下一个元素。对于每对元素,我们将键和值放入结果 HashMap 中,就像前一个示例中一样。

7. 结论

在本文中,我们通过示例学习了三种将两个给定List合并为 Map 的方法。 首先,我们基于随机访问的列表使用了 for 循环和 Stream 解决了这个问题。然后,我们讨论了随机访问方法的性能问题,当我们的输入是 LinkedList 时。 最后,我们看到了基于 Iterator 的解决方案,这样无论我们有哪种 List 实现,都可以获得更好的性能。 像往常一样,这里介绍的所有代码片段都可以在 GitHub 上找到。

原文链接:https://www.baeldung.com/java-combine-two-lists-into-map

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2023-05-03,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 2. 问题介绍
  • 3. 关于验证的说明
  • 4. 循环填充 Map
  • 5. 使用 Stream API
  • 6. 使用 Iterator
  • 7. 结论
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档