LoginSignup
3
3

More than 5 years have passed since last update.

map[key1,key2]形式で複数キー用マップを操作する(Groovy)

Last updated at Posted at 2015-09-29

やりたいこと

ペア(やセット)に対して値(やオブジェクト)を設定したい場合があります。
(例)

  • ニューラルネットワーク計算での2ユニット間の「重み」
  • ソーシャルネットワークにおけるユーザ間の距離とか

一致や比較について特別な要件がある場合は、ペアやグループを保持する専用クラスを作って、equals()やhashcode()をoverrideするようにし、comparatorも設定し、その専用クラスをMapのキーにする、という感じだと思います。

しかし、ただペアやセットを、別の何かと一対一対応させたいだけなら、Listをキーにすれば済み(順不同にする工夫は必要)、それもよくやられていると思います。

今回は、それをGroovyでやってみると、値を登録/取得するコードがシンプルで気持ちいいという話です。

実装例

複数キー対応マップクラス:

class MultiKeyMap extends HashMap<List,Object>{
    @Override
    Object put(List key, Object value) {
        super.put(key.sort(false), value)
    }
    @Override
    Object get(Object key) { // get(List key)とすると呼ばれなくなってしまう
        super.get((key as List).sort(false))
    }
}

使用例:

class Neuron{} // ネットワークのニューロン(ユニット)、中身は省略

があるとして、

def w = new MultiKeyMap() // ニューロン間の重み(ペアごとに設定される)マップ

def n1 = new Neuron()
def n2 = new Neuron()
def n3 = new Neuron()

w[n1,n2] = 0.2 // 値をセット
println w[n1,n2] // 取得できる
assert w[n1,n2] == w[n2,n1] // もちろん順不同
.
w[n1,n2,n3] = 0.5 // 3要素以上の組でもOK
println w[n1,n2,n3]

ポイント

Groovyのマップにおいて、mapObj[a,b,c]は、mapObj[[a,b,c]]と同じで、
つまり「[a,b,c]というリストをキーにしてmapObjから値を取得する」動きになります。
複数キーマップとして使い勝手のよい最小表現は、

  1. mapObj[a,b] ← 今回はこれ
  2. mapObj[a][b] // 二次元配列、numpyの行列とか
  3. mapObj(a,b)

かなと思うのですが、1.の形は比較的簡単に実現できて便利だな、というところです。

※2.も実装できないことはないのですが、速度やメモリに無駄な部分が出てくる予感です。
また、numpyの行列が一層便利だと思う点は、ワイルドカードを使って、w[a][*](aを含むすべてのペアの値を返す)のような書き方ができることです。

3
3
0

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
3
3