Using streams, how can I map the values in a HashMap?

后端 未结 3 624
没有蜡笔的小新
没有蜡笔的小新 2020-12-17 08:00

Given a Map where Person has a String getName() (etc) method on it, how can I turn the Map

相关标签:
3条回答
  • 2020-12-17 08:15

    One way is to use a toMap collector:

    import static java.util.stream.Collectors.toMap;
    
    Map<String, String> byNameMap = people.entrySet().stream()
                                         .collect(toMap(Entry::getKey, 
                                                        e -> e.getValue().getName()));
    
    0 讨论(0)
  • 2020-12-17 08:20

    With Java 8 you can do:

    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.

    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 down with Collectors.toMap like this:

    Map<String, String> byNameMap = people.entrySet()
      .stream()
      .collect(Collectors.toMap(Map.Entry::getKey, (entry) -> entry.getValue().getName());
    
    0 讨论(0)
  • 2020-12-17 08:33

    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.

    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());
    
    0 讨论(0)
提交回复
热议问题