HashMapの値を反復してコピーする効率的な方法


9

変換したい:

Map<String, Map<String, List<Map<String, String>>>> inputMap 

に:

Map<String, Map<String, CustomObject>> customMap

inputMap構成で提供され、準備ができていますが、customMapフォーマットする必要があります。CustomObjectはList<Map<String, String>>、関数で数行のコードを使用することから派生します。

入力マップを反復し、customMapでキー値をコピーする通常の方法を試しました。Java 8または他のショートカットを使用してそれを行う効率的な方法はありますか?

Map<String, Map<String, List<Map<String, String>>>> configuredMap = new HashMap<>();
Map<String, Map<String, CustomObj>> finalMap = new HashMap<>();


for (Map.Entry<String, Map<String, List<Map<String, String>>>> attributeEntry : configuredMap.entrySet()) {
    Map<String, CustomObj> innerMap = new HashMap<>();
    for (Map.Entry<String, List<Map<String, String>>> valueEntry : attributeEntry.getValue().entrySet()) {
        innerMap.put(valueEntry.getKey(), getCustomeObj(valueEntry.getValue()));
    }
    finalMap.put(attributeEntry.getKey(), innerMap);
}

private CustomObj getCustomeObj(List<Map<String, String>> list) {
    return new CustomObj();
}

コードを適切にフォーマットしてください。
akuzminykh

1
コピーするのではなく、ファサードを作成することを考えましたか?
ControlAltDel

これ以上効率的な方法はありません。これらの操作はすべて実行する必要があります。しかし、このコードは実際には機能しません。リストをカスタムオブジェクトに入れていません。
user207421

回答:


2

1つの解決策は、entrySetof をストリーミングしてからinputMapCollectors#toMap2回使用することです(1回はouter Mapに、1回はinnerにMap)。

Map<String, Map<String, CustomObj>> customMap = inputMap.entrySet()
        .stream()
        .collect(Collectors.toMap(Function.identity(), entry -> {
            return entry.getValue()
                        .entrySet()
                        .stream()
                        .collect(Collectors.toMap(Function.identity(), 
                            entry -> getCustomeObj(entry.getValue())));
        }));

あなたは省略することができます{}:、ラムダにこのような何かとreturn文を.collect(Collectors.toMap(Function.identity(), entry -> entry.getValue() .entrySet() .stream() .collect(Collectors.toMap(Function.identity(), entry -> getCustomeObj(entry.getValue()))); ));
祥子

3
@SHoko確かに、ブロックがないと読みにくくなります。
Jacob G.

1

ストリーミングはできますが、読みやすくはありません。少なくとも私には。したがって、メソッドがある場合:

static CustomObject fun(List<Map<String, String>> in) {
    return .... // whatever processing you have here
}

java-8構文を使用することもできますが、別の形式です。

    Map<String, Map<String, CustomObject>> customMap = new HashMap<>();

    inputMap.forEach((key, value) -> {

        value.forEach((innerKey, listOfMaps) -> {

            Map<String, CustomObject> innerMap = new HashMap<>();
            innerMap.put(innerKey, fun(listOfMaps));
            customMap.put(key, innerMap);

        });
    });

内部マップを作成できる場合はimmutable、さらに短くすることができます。

inputMap.forEach((key, value) -> {
      value.forEach((innerKey, listOfMaps) -> {
          customMap.put(key, Collections.singletonMap(innerKey, fun(listOfMaps)));
      });
});

1

私見ストリーミングはそれほど悪い考えではありません。悪いツールはありません。それはあなたがそれらをどのように使っているかに依存します。


この特定のケースでは、繰り返しパターンをユーティリティメソッドに抽出します。

public static <K, V1, V2> Map<K, V2> transformValues(Map<K, V1> map, Function<V1, V2> transformer) {
    return map.entrySet()
              .stream()
              .collect(toMap(Entry::getKey, e -> transformer.apply(e.getValue())));
}

上記の方法は、どのアプローチを使用しても実装できますが、Stream APIここではかなりうまくいくと思います。


ユーティリティメソッドを定義すると、次のように簡単に使用できます。

Map<String, Map<String, CustomObj>> customMap = 
    transformValues(inputMap, attr -> transformValues(attr, this::getCustomObj));

実際の変換は事実上1つのライナーです。したがって、適切なJavaDocfor transformValuesメソッドを使用すると、結果コードはかなり読みやすく、保守が容易になります。


1

次のようCollectors.toMapな外部レベルと内部レベルの両方のエントリについてはどうですか。

Map<String, Map<String, CustomObj>> finalMap = configuredMap.entrySet()
        .stream()
        .collect(Collectors.toMap(Map.Entry::getKey,
                attributeEntry -> attributeEntry.getValue().entrySet()
                        .stream()
                        .collect(Collectors.toMap(Map.Entry::getKey,
                                valueEntry -> getCustomeObj(valueEntry.getValue())))));
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.