如何使用Google Collections将List<String>转换为Map<String,String>?

51
我有一个字符串列表并且有一个函数可以为列表中的每个键生成一个值。我想使用这个函数创建一个映射表。我能用Google Collections实现吗?

我假设你已经知道了,但如果函数生成的值可能对于原始列表中的任何两个元素都相同,那么你需要使用 Multimaps.index 生成一个 Multimap,它可以为相同的键存储多个值。 - ColinD
5个回答

88

使用 Maps.uniqueIndex(Iterable, Function):

返回一个不可变的 Map,其中 Map.values() 是给定元素按照给定顺序排列的结果,并且每个 key 都是对应 value 应用提供的函数后得到的乘积。(来自 javadoc)

示例:

Map<String,String> mappedRoles = Maps.uniqueIndex(yourList, new Function<String,String>() {
  public String apply(String from) {
    // do stuff here
    return result;
  }});

2
这个解决方案的性能如何?我想在一个大对象列表中使用它来处理50,000+个元素。我目前使用两个单独的映射,存储相同的对象,但映射到不同的键。我想摆脱这些映射并使用一个列表(因为键已经是对象的字段)。你的解决方案允许我从列表自动生成地图。但代价是什么? - m_pGladiator
@m_pGladiator 我知道你的问题已经很久了,但答案可能会对其他人有所帮助...我认为Guava方法通常更多地提供方便/可读性,而不是性能。如果你有疑问,最好还是手动编写循环。或者使用像Caliper这样的工具来测量各自的性能。 - PhiLho
OP说他们有“一个[函数]为列表中的每个键生成值”。Maps.uniqueIndex为列表中的每个值生成键,这与OP所要求的相反。因此,这个答案和Sean的答案是不正确的,而ColinD的答案是正确的。 - Marcin

23
截至2012年7月26日,Guava主分支添加了两种新方法来实现这一点。它们应该在14.0版本中发布。
Maps.asMap(Set<K>, Function<? super K, V>)(以及SortedSet和NavigableSet的两个重载)允许您将SetFunction视为一个Map,其中集合中每个键的值是将该键应用于函数的结果。结果是一个视图,因此它不会复制输入集合,并且Map结果将随着集合的更改而更改,反之亦然。
Maps.toMap(Iterable<K>, Function<? super K, V>)接受一个Iterable并急切地将其转换为一个ImmutableMap,其中可迭代的不同元素是键,而每个键上应用函数的结果则是对应的值。

15

编辑:Sean可能是对的,我可能误解了问题。

如果原始列表是指keys,那么似乎你可以通过MapMaker.makeComputingMap使用计算映射,并忽略输入列表。 编辑:如评论中所述,这在Guava 15.0中已被弃用和删除。 另请查看CacheBuilder

另一方面,这也不会给你一个地图,如果你问它一个起始列表中没有的键对应的值,它将返回null。换句话说,这可能是不合适的,但根据你想要做什么,这也值得考虑。 :)

除非您评论说都不有用,否则我会把这个答案留在这里,否则我会删除它。


原始回答

使用Guava,您可以使用Maps.uniqueIndex轻松完成此操作:

Map<String, String> map = Maps.uniqueIndex(list, keyProjection);

我特别提到了Guava而不是Google collections,因为我没有检查旧的Google collections存储库是否包括Maps.uniqueIndex


makeComputingMap已被弃用,并计划很快删除。http://code.google.com/p/guava-libraries/wiki/MapMakerMigration - ripper234
@ripper234:谢谢,已经添加了CacheBuilder的链接。 - Jon Skeet
我考虑在我的原始评论中添加一个链接,但是从CacheBuilder中获取Map是否容易? - ripper234

13

1
是的,我认为你可能是对的。我编辑了我的答案,提到了计算地图,以防这适合OP,但我也非常愿意完全删除答案。 - Jon Skeet

6

Using Guava + Lambda

 Map<String, YourCustomClass> map = Maps.uniqueIndex(YourList, YourCustomClass -> YourCustomClass.getKey());

3
如果您可以使用lambda表达式,就可以放弃使用guava并改用Java8的Stream API。 - Toilal
2
除非您正在开发 Android 版本低于 7.0 的应用。 - user1209216

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