[英]Using streams, how can I map the values in a HashMap?
Given a Map<String, Person>
where Person has a String getName()
(etc) method on it, how can I turn the Map<String, Person>
into a Map<String, String>
where the String
is obtained from calling Person::getName()
?给定一个
Map<String, Person>
,其中 Person 有一个String getName()
(等)方法,我怎样才能将Map<String, Person>
变成一个Map<String, String>
,其中String
是从调用Person::getName()
获得的Person::getName()
?
Pre-Java 8 I'd use我会使用 Pre-Java 8
Map<String, String> byNameMap = new HashMap<>();
for (Map.Entry<String, Person> person : people.entrySet()) {
byNameMap.put(person.getKey(), person.getValue().getName());
}
but I'd like to do it using streams and lambdas.但我想使用流和 lambda 来做到这一点。
I can't see how to do this in a functional style: Map/HashMap don't implement Stream
.我看不到如何以功能样式执行此操作: Map/HashMap 不实现
Stream
。
people.entrySet()
returns a Set<Entry<String, Person>>
which I can stream over, but how can I add a new Entry<String, String>
to the destination map? people.entrySet()
返回一个Set<Entry<String, Person>>
我可以在 ZF7B44CFFAFD5C52223D5498196C8A2E7BZ 上,但是如何将新的Entry<String, String>
添加到目标 map?
With Java 8 you can do:使用 Java 8,您可以执行以下操作:
Map<String, String> byNameMap = new HashMap<>();
people.forEach((k, v) -> byNameMap.put(k, v.getName());
Though you'd be better off using Guava's Maps.transformValues , which wraps the original Map
and does the conversion when you do the get
, meaning you only pay the conversion cost when you actually consume the value.尽管您最好使用 Guava 的Maps.transformValues ,它包装原始
Map
并在您执行get
时进行转换,这意味着您仅在实际消耗该值时才支付转换成本。
Using Guava would look like this:使用番石榴看起来像这样:
Map<String, String> byNameMap = Maps.transformValues(people, Person::getName);
EDIT:编辑:
Following @Eelco's comment (and for completeness), the conversion to a map is better done with Collectors.toMap like this:按照@Eelco 的评论(为了完整性),使用Collectors.toMap更好地转换为地图,如下所示:
Map<String, String> byNameMap = people.entrySet()
.stream()
.collect(Collectors.toMap(Map.Entry::getKey, (entry) -> entry.getValue().getName());
One way is to use a toMap
collector:一种方法是使用
toMap
收集器:
import static java.util.stream.Collectors.toMap;
Map<String, String> byNameMap = people.entrySet().stream()
.collect(toMap(Entry::getKey,
e -> e.getValue().getName()));
Using a bit of generic code that I've sadly not found in the libraries I had at hand使用一些我手头的库中没有找到的通用代码
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())
));
}
This becomes essentially the same as Guavas Maps.transformValues
minus the downsides mentioned by others.这与 Guavas
Maps.transformValues
基本相同,减去其他人提到的缺点。
Map<String, Person> persons = ...;
Map<String, String> byNameMap = remap(persons, Person::getName);
And in case you need the key as well as the value in your remapping function, this second version makes that possible如果您需要重新映射函数中的键和值,第二个版本使这成为可能
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())
));
}
It can be used for example like它可以用于例如
Map<String, String> byNameMap = remap(persons, (key, val) -> key + ":" + val.getName());
Since Java 9 you can also do:由于 Java 9 你也可以这样做:
Entry<String, String> entry = Map.entry("a", "b");
In your Map it would be used like this:在您的 Map 中,它将像这样使用:
Map<String, String> byNameMap = people.entrySet()
.stream()
.map(entry -> Map.entry(entry.getKey(), entry.getValue().getName()))
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue);
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.