43

给定Map<String, Person>where Person 有一个String getName()(等)方法,我怎样才能把它Map<String, Person>变成一个Map<String, String>where theString是从调用中获得的Person::getName()

我会使用 Pre-Java 8

Map<String, String> byNameMap = new HashMap<>();

for (Map.Entry<String, Person> person : people.entrySet()) {
    byNameMap.put(person.getKey(), person.getValue().getName());
}

但我想使用流和 lambda 来做到这一点。

我看不到如何以功能样式执行此操作: Map/HashMap don't implement Stream.

people.entrySet()返回一个Set<Entry<String, Person>>我可以流式传输的,但是如何Entry<String, String>向目标地图添加一个新的?

4

3 回答 3

54

使用 Java 8,您可以:

Map<String, String> byNameMap = new HashMap<>();
people.forEach((k, v) -> byNameMap.put(k, v.getName());

尽管您最好使用 Guava 的Maps.transformValues,它会包装原始文件Map并在您执行转换时进行转换get,这意味着您只需在实际消耗价值时支付转换费用。

使用番石榴看起来像这样:

Map<String, String> byNameMap = Maps.transformValues(people, Person::getName);

编辑:

根据@Eelco 的评论(为了完整起见),最好使用Collectors.toMap转换为地图,如下所示:

Map<String, String> byNameMap = people.entrySet()
  .stream()
  .collect(Collectors.toMap(Map.Entry::getKey, (entry) -> entry.getValue().getName());
于 2014-04-03T14:17:07.377 回答
26

一种方法是使用toMap收集器:

import static java.util.stream.Collectors.toMap;

Map<String, String> byNameMap = people.entrySet().stream()
                                     .collect(toMap(Entry::getKey, 
                                                    e -> e.getValue().getName()));
于 2014-04-03T14:13:32.963 回答
2

使用一些我在手头的库中没有找到的通用代码

public static <K, V1, V2> Map<K, V2> remap(Map<K, V1> map,
        Function<? super V1, ? extends V2> function) {

    return map.entrySet()
            .stream() // or parallel
            .collect(Collectors.toMap(
                    Map.Entry::getKey, 
                    e -> function.apply(e.getValue())
                ));
}

Maps.transformValues这与番石榴减去其他人提到的缺点基本相同。

Map<String, Person> persons = ...;
Map<String, String> byNameMap = remap(persons, Person::getName);

如果您需要重新映射函数中的键和值,第二个版本使这成为可能

public static <K, V1, V2> Map<K, V2> remap(Map<K, V1> map,
        BiFunction<? super K, ? super V1, ? extends V2> function) {

    return map.entrySet()
            .stream() // or parallel
            .collect(Collectors.toMap(
                    Map.Entry::getKey,
                    e -> function.apply(e.getKey(), e.getValue())
                ));
}

它可以用于例如

Map<String, String> byNameMap = remap(persons, (key, val) -> key + ":" + val.getName());
于 2018-06-07T11:54:56.357 回答