LoginSignup
0
0

More than 3 years have passed since last update.

マルチキーマップを標準ライブラリで作る

Posted at

複数のキーを持つマップが必要な場合、サードパーティー製のライブラリを使う方法もありますが、標準ライブラリのMapをネストさせる方法もあります。
ここでは3つのキーを持つマップを例とします。
最初はget()です。指定したキーを持つ値が存在しない場合はnullを返します。

public static <A, B, C, D> D get(Map<A, Map<B, Map<C, D>>> map, A a, B b, C c) {
    return Optional.ofNullable(map.get(a))
        .map(m -> m.get(b))
        .map(m -> m.get(c))
        .orElse(null);
}

次はput()です。

public static <A, B, C, D> void put(Map<A, Map<B, Map<C, D>>> map, A a, B b, C c, D d) {
    map.computeIfAbsent(a, t -> new HashMap<>())
        .computeIfAbsent(b, t -> new HashMap<>())
        .put(c, d);
}

パターンがわかれば4つ以上のキーを持つマップも簡単に作れると思います。
以下はテストコードです。

@Test
public void testMultiKeyMap() {
    Map<Integer, Map<Integer, Map<Integer, Integer>>> map = new HashMap<>();
    for (int a = 0, value = 0; a < 2; ++a)
        for (int b = 0; b < 2; ++b)
            for (int c = 0; c < 2; ++c)
                put(map, a, b, c, value++);
    Map<Integer, Map<Integer, Map<Integer, Integer>>> expected =
        Map.of(0, Map.of(0, Map.of(0, 0,
                                   1, 1),
                         1, Map.of(0, 2,
                                   1, 3)),
               1, Map.of(0, Map.of(0, 4,
                                   1, 5),
                         1, Map.of(0, 6,
                                   1, 7)));
    assertEquals(expected, map);
    for (int a = 0, value = 0; a < 2; ++a)
        for (int b = 0; b < 2; ++b)
            for (int c = 0; c < 2; ++c)
                assertEquals(value++, get(map, a, b, c));
    assertEquals(null, get(map, 2, 2, 2));
}

map.toString()は以下のようになります。

{0={0={0=0, 1=1}, 1={0=2, 1=3}}, 1={0={0=4, 1=5}, 1={0=6, 1=7}}}
0
0
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0