web-dev-qa-db-ja.com

Java 8では、ラムダを使用してMap <K、V>を別のMap <K、V>に変換するにはどうすればよいですか?

Java 8を調べ始めたばかりで、ラムダを試してみるために、最近書​​いた非常に簡単なものを書き直そうと思いました。 String to ColumnのMapを、新しいMapのColumnが最初のMapのColumnの防御コピーであるString to Columnの別のMapに変換する必要があります。列にはコピーコンストラクターがあります。これまでで一番近いのは:

    Map<String, Column> newColumnMap= new HashMap<>();
    originalColumnMap.entrySet().stream().forEach(x -> newColumnMap.put(x.getKey(), new Column(x.getValue())));

しかし、それを行うにはもっと良い方法があるに違いないと確信しており、いくつかのアドバイスに感謝します。

120
annesadleir

Collector を使用できます。

import Java.util.*;
import Java.util.stream.Collectors;

public class Defensive {

  public static void main(String[] args) {
    Map<String, Column> original = new HashMap<>();
    original.put("foo", new Column());
    original.put("bar", new Column());

    Map<String, Column> copy = original.entrySet()
        .stream()
        .collect(Collectors.toMap(Map.Entry::getKey,
                                  e -> new Column(e.getValue())));

    System.out.println(original);
    System.out.println(copy);
  }

  static class Column {
    public Column() {}
    public Column(Column c) {}
  }
}
189
McDowell
Map<String, Integer> map = new HashMap<>();
map.put("test1", 1);
map.put("test2", 2);

Map<String, Integer> map2 = new HashMap<>();
map.forEach(map2::put);

System.out.println("map: " + map);
System.out.println("map2: " + map2);
// Output:
// map:  {test2=2, test1=1}
// map2: {test2=2, test1=1}

forEachメソッドを使用して、必要な処理を実行できます。

あなたがそこでしていることは:

map.forEach(new BiConsumer<String, Integer>() {
    @Override
    public void accept(String s, Integer integer) {
        map2.put(s, integer);     
    }
});

これをラムダに単純化できます:

map.forEach((s, integer) ->  map2.put(s, integer));

そして、既存のメソッドを呼び出しているだけなので、 method reference を使用できます。

map.forEach(map2::put);
22
Arrem

すべてのエントリを新しいマップに再挿入しない方法が最速です HashMap.cloneが内部的に再ハッシュを実行するため、そうはなりません。

Map<String, Column> newColumnMap = originalColumnMap.clone();
newColumnMap.replaceAll((s, c) -> new Column(c));
12
leventov

シンプルにしてJava 8を使用してください:-

 Map<String, AccountGroupMappingModel> mapAccountGroup=CustomerDAO.getAccountGroupMapping();
 Map<String, AccountGroupMappingModel> mapH2ToBydAccountGroups = 
              mapAccountGroup.entrySet().stream()
                         .collect(Collectors.toMap(e->e.getValue().getH2AccountGroup(),
                                                   e ->e.getValue())
                                  );
7
Anant Khurana

プロジェクトでGuava(v11以上)を使用する場合、 Maps :: transformValues を使用できます。

Map<String, Column> newColumnMap = Maps.transformValues(
  originalColumnMap,
  Column::new // equivalent to: x -> new Column(x) 
)
2
Andrea Bergonzo

何らかの変換を行う必要がある場合に、キーと値に同時にアクセスできる別の方法を次に示します。

Map<String, Integer> pointsByName = new HashMap<>();
Map<String, Integer> maxPointsByName = new HashMap<>();

Map<String, Double> gradesByName = pointsByName.entrySet().stream()
        .map(entry -> new AbstractMap.SimpleImmutableEntry<>(
                entry.getKey(), ((double) entry.getValue() /
                        maxPointsByName.get(entry.getKey())) * 100d))
        .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
2
Lucas Ross

サードパーティのライブラリを使用してもかまわない場合、my cyclops-react libには Map を含むすべての JDK Collection タイプの拡張機能があります。マップまたはbimapメソッドを直接使用して、マップを変換できます。 MapXは、既存のマップから構築できます。

  MapX<String, Column> y = MapX.fromMap(orgColumnMap)
                               .map(c->new Column(c.getValue());

キーも変更したい場合は、書くことができます

  MapX<String, Column> y = MapX.fromMap(orgColumnMap)
                               .bimap(this::newKey,c->new Column(c.getValue());

bimapは、キーと値を同時に変換するために使用できます。

MapXがMapを拡張すると、生成されたマップは

  Map<String, Column> y
1
John McClean