2016-03-24 9 views
7

ストリーム:地図<文字列、リスト<String>のJavaをマージ8私はJAVA 8ストリームを持つ2つの地図をマージしたい

Map<String, List<String>> mapGlobal = new HashMap<String, List<String>>(); 
Map<String, List<String>> mapAdded = new HashMap<String, List<String>>(); 

私はこの実装を使用してみてください:しかし

mapGlobal = Stream.of(mapGlobal, mapAdded) 
       .flatMap(m -> m.entrySet().stream()) 
       .collect(Collectors.groupingBy(Map.Entry::getKey, 
         Collectors.mapping(Map.Entry::getValue,   
              Collectors.toList()) 
       )); 

を、この実装

Map<String, List<Object>>

:だけのような結果を作成します1つのキーがmapGlobalに含まれていない場合は、対応するストリングのリストと共に新しいキーとして追加されます。キーがmapGlobalmapAddedに複製されている場合、両方の値のリストは、A = {1, 3, 5, 7}B = {1, 2, 4, 6}A ∪ B = {1, 2, 3, 4, 5, 6, 7}のようにマージされます。

答えて

7

mapAddedのすべてのエントリを繰り返し、mapGlobalにマージすると、これを行うことができます。

以下は、のエントリに対して、forEach(action)を呼び出すことによって反復します。ここで、アクションは各エントリのキーと値を消費します。各エントリについて、をmapGlobalに呼び出します。これは、キーが存在しない場合はkの下にエントリを作成し、値がvの場合、または存在する場合は指定の再マッピング関数を呼び出します。この関数は、この場合には、最初のユニークな要素をソートし、リストに逆変換の両方を確保するためにTreeSetに追加され、マージする2個のリストを取ります。

mapAdded.forEach((k, v) -> mapGlobal.merge(k, v, (v1, v2) -> { 
    Set<String> set = new TreeSet<>(v1); 
    set.addAll(v2); 
    return new ArrayList<>(set); 
})); 

あなたが並列に潜在的にそれを実行したい場合ストリームパイプラインを作成するには、entrySet()を取得し、parallelStream()を呼び出します。しかし、ConcurrentHashMapのように、mapGlobalの同時性をサポートするマップを使用することを確認する必要があります。

ConcurrentMap<String, List<String>> mapGlobal = new ConcurrentHashMap<>(); 
// ... 
mapAdded.entrySet().parallelStream().forEach(e -> mapGlobal.merge(e.getKey(), e.getValue(), (v1, v2) -> { 
    Set<String> set = new TreeSet<>(v1); 
    set.addAll(v2); 
    return new ArrayList<>(set); 
})); 
+0

この実装では、ストリームコレクションの改善は使用されません。両方のマップが巨大な場合、私はparallelStream()のようなものを使用したいと思います。それは可能ですか? – ypriverol

+2

@ypriverolはい、あなたはそれを編集することができます。 – Tunaki

+2

'mapGlobal'が' ConcurrentMap'でない限り、パラレルストリームの内部からそれを変更することは安全ではありません。 – Misha

1

foreach overマップマップを使用して、マップを結果マップに結合されたArrayListの値にマージします。

public Map<String, ArrayList<String>> merge(Map<String, ArrayList<String>> map1, Map<String, ArrayList<String>> map2) { 
    Map<String, ArrayList<String>> map = new HashMap<>(); 
    map.putAll(map1); 

    map2.forEach((key , value) -> { 
     //Get the value for key in map. 
     ArrayList<String> list = map.get(key); 
     if (list == null) { 
      map.put(key,value); 
     } 
     else { 
      //Merge two list together 
      ArrayList<String> mergedValue = new ArrayList<>(value); 
      mergedValue.addAll(list); 
      map.put(key , mergedValue); 
     } 
    }); 
    return map; 
} 
1

オリジナルの実装はMap<String, List<Object>>が、Map<String, List<List<String>>>のような結果を作成しません。 Map<String, List<String>>を生成するには、追加のストリームパイプラインが必要です。

関連する問題