JavaとPythonにおける辞書の遅延初期化と値の更新

キーが存在しない場合にその値を動的に生成し、存在する場合は既存の値を操作する処理は、マップ構造を扱う際に頻出するパターンである。JavaとPythonでは、それぞれ異なるメカニズムでこのニーズを効率的に解決できる。

Java: computeIfAbsent の活用

従来の実装では、キーの存在確認と値の初期化を分けて記述していた。

import java.util.*;

public class DictionaryExample {
    public static void main(String[] args) {
        HashMap<String, Set<String>> countryToPersons = new HashMap<>();
        Set<String> initialSet = new HashSet<>();
        initialSet.add("張三");
        initialSet.add("王五");
        countryToPersons.put("中国", initialSet);

        // 旧方式:存在チェックと初期化を分離
        if (countryToPersons.containsKey("フランス")) {
            countryToPersons.get("フランス").add("李四");
        } else {
            Set<String> newSet = new HashSet<>();
            newSet.add("李四");
            countryToPersons.put("フランス", newSet);
        }
    }
}

Java 8以降では、computeIfAbsentメソッドにより、この処理を1行で簡潔に記述可能である。

import java.util.*;

public class DictionaryExample {
    public static void main(String[] args) {
        HashMap<String, Set<String>> countryToPersons = new HashMap<>();
        Set<String> initialSet = new HashSet<>();
        initialSet.add("張三");
        initialSet.add("王五");
        countryToPersons.put("中国", initialSet);

        // 新方式:キーが存在しない場合のみSetを生成し、要素を追加
        countryToPersons.computeIfAbsent("フランス", k -> new HashSet<>()).add("李四");

        System.out.println(countryToPersons); // {中国=[張三, 王五], フランス=[李四]}
    }
}

computeIfAbsentは、指定したキーがマップに存在しない場合にのみラムダ式を実行し、返された値をキーと関連付けて格納する。存在する場合は既存の値を返し、その参照に対して直接操作(例:.add())が可能である。

Python: setdefault と defaultdict の選択

Pythonでは、同様の挙動をsetdefaultメソッドまたはcollections.defaultdictで実現できる。

setdefaultを使用する例:

country_to_persons = {"中国": {"張三", "李四"}}
country_to_persons.setdefault("フランス", set()).add("王五")
print(country_to_persons)
# {'中国': {'張三', '李四'}, 'フランス': {'王五'}}

setdefaultはキーが存在しない場合にデフォルト値を設定し、その値を返す。この返されたオブジェクトに対して直接メソッドを呼び出せるため、1行で更新が可能である。

より洗練されたアプローチとして、defaultdictを用いる方法がある。

from collections import defaultdict

country_to_persons = defaultdict(set)
country_to_persons["中国"] = {"張三", "李四"}
country_to_persons["フランス"].add("王五")

print(dict(country_to_persons))
# {'中国': {'張三', '李四'}, 'フランス': {'王五'}}

defaultdictは、キーが存在しないときに自動的に指定されたファクトリ関数(ここではset())を呼び出して初期化する。このため、country_to_persons["フランス"]を参照するだけで、内部で空のsetが生成され、add()が即座に適用可能となる。この方式は、複数のキーに対して同様の初期化ロジックを適用する場合に特に有効である。

タグ: Java Python computeIfAbsent defaultdict setdefault

6月13日 22:56 投稿