読者です 読者をやめる 読者になる 読者になる

Clojure でマップのキーとバリューを反転させるのどーするの?

SWTウィジェットのスタイルを設定したり、取得するとき、キーワードの配列として設定したり、取得したりすると便利だと思いますた。
キーの配列をビットフィールドに変換して .setStyle に渡すのはうまくいったんだけど、
そのビットフィールドをキーワードの配列に変換して返さないとうまくないよなーこれということになり…。(あらすじ)

結局のところ、widgets.clj の 167 行目からの to-style-value 関数の様な形になったんだけど、ちょいと難しかった。

(defn- to-style-value [a_style-alist swt-style-value]
  (let [reverse-alist (apply assoc {} (interleave (vals a_style-alist) (keys a_style-alist)))
        has-vlist (filter pos? (map #(bit-and (a_style-alist %) swt-style-value) (keys a_style-alist)))]
    (map #(get reverse-alist %) has-vlist)))

第一引数の a_style-alist が、キーワードと SWT のスタイルを表す定数のマップで、 第二引数の swt-style-valueSWT のスタイル用定数を bit-or でくっつけたもの。

let 内変数の reverse-alista_style-alist を反転させたもの。

(interleave (vals a_style-alist) (keys a_style-alist))

とやるだけでは、バリュー・値と並んだ配列になってしまうんだ。
これをマップにしてくれるのが applyassoc
ぶっちゃけると、なぜそーなるかは知らないw

(filter pos? (map #(bit-and (a_style-alist %) swt-style-value) (keys a_style-alist)))

swt-style-valueSWT のスタイル定数のいずれかを必ず含んでいるので、 bit-and を使うとどれを含んでいるのかがわかるよね。
ということでもうひとつの let 内変数の has-vlistswt-style-value に含まれている SWT のスタイル定数の配列になってるよ。

これをキーに、reverse-alist につっこむと、キーワードの配列を得ることができるよ!できるよ!

ヽ(゚∀゚)ノ ワー

P.S.

だんだん寒くなってきましたね。お元気ですか? 私は元気です。
このエントリを書いていたところ、私はあることに気づきました。
それは、let の中の変数への値に (keys a_style-alist) が共通して含まれていることです。

であれば:

(defn- to-style-value [a_style-alist swt-style-value]
  (let [style-keys (keys a_style-alist)
        reverse-alist (apply assoc {} (interleave (vals a_style-alist) style-keys))
        has-vlist (filter pos? (map #(bit-and (a_style-alist %) swt-style-value) style-keys))]
    (map #(get reverse-alist %) has-vlist)))

このように書いてもいいのではないでしょうか?