web-dev-qa-db-ja.com

Merge Map <String、List <String> Java 8 Stream

Java 8 Stream:

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}

16
ypriverol

これを行うには、mapAddedのすべてのエントリを繰り返し処理し、mapGlobalにマージします。

次のコードは、 forEach(action) を呼び出してmapAddedのエントリを反復処理し、アクションが各エントリのキーと値を消費します。エントリごとに、mapGlobalmerge(key, value, remappingFunction) を呼び出します。これにより、キーkの下にエントリが作成され、キーが存在しない場合は値vが作成されます。指定された再マッピング関数が既に存在する場合は、それらを呼び出します。この関数は、マージする2つのリストを取得します。この場合、最初にTreeSetに追加され、一意の要素と並べ替えられた要素の両方を確実にし、リストに変換し直します。

_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()を呼び出すことにより、Streamパイプラインを作成できます。ただし、その場合は、mapGlobalのように、ConcurrentHashMapの同時実行をサポートするマップを使用する必要があります。

_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);
}));
_
19
Tunaki

Foreach over Mapを使用すると、指定された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;
}
4
swapnil

元の実装はMap<String, List<Object>>のような結果を作成しませんが、Map<String, List<List<String>>>を作成します。 Map<String, List<String>>を生成するには、追加のStreamパイプラインが必要です。

2
Sergei Veselev

StreamEx の使用

Map<String, List<String>> mergedMap =
        EntryStream.of(mapGlobal)
                .append(EntryStream.of(mapAdded))
                .toMap((v1, v2) -> {
                    List<String> combined = new ArrayList<>();
                    combined.addAll(v1);
                    combined.addAll(v2);
                    return combined;
                });

マージするマップがさらにある場合は、ストリームに追加するだけです

                .append(EntryStream.of(mapAdded2))
                .append(EntryStream.of(mapAdded3))
0
Jay