TIL

Today I Learned. 知ったこと、学んだことを書いていく

連想配列(alist) - Lisp

Lispには連想リストというものがある

連想リスト(association list)、また、alistと呼ばれる。carがキー、cdrが値となる。

carがキー、cdrが値って考え方スッキリしてて好き

> (defparameter *alist* '((hoge (1 2 3))
                          (fuga (4 5 6))
                          (piyo (7 8 9))))
*ALIST*

> *alist*
((HOGE (1 2 3)) (FUGA (6 7 8)) (PIYO (9 1 2)))

要素の追加にはconsを使う

> *alist*
((HOGE (1 2 3)) (FUGA (4 5 6)) (PIYO (7 8 9)))

> (cons (cons 'hogera '(10 11 12)) *alist*)
((HOGERA 10 11 12) (HOGE (1 2 3)) (FUGA (4 5 6)) (PIYO (7 8 9)))

先頭に追加のときはpushを使うのが楽かも

> *alist*
((HOGE (1 2 3)) (FUGA (4 5 6)) (PIYO (7 8 9)))

> (push '(foo (a b c)) *alist*)
((FOO (A B C)) (HOGE (1 2 3)) (FUGA (4 5 6)) (PIYO (7 8 9)))

キーを指定して値を取得

assoc関数を使うことで指定したキーに一致するリストが取得できる

> (assoc 'hoge *alist*)
(HOGE (1 2 3))

値のみ取得したい場合

> (cadr (assoc 'hoge *alist*))
(1 2 3)

assocとpushで値を更新したように見せかける

assocは見つかった最初の要素を返すため、pushすると(最初の要素に追加)、値を更新したことと同じになる。最初、何言ってるのかわかんなくて全然理解できなかった。

> (defparameter *fruits* '((apple (100 red))
                           (banana (150 yellow))
                           (peach (300 pink))))
*FRUITS*

> *fruits*
((APPLE (100 RED)) (BANANA (150 YELLOW)) (PEACH (300 PINK)))

> (assoc 'peach *fruits*)
(PEACH (300 PINK))

;;; 最初の要素に追加
> (push '(peach (500 pink)) *fruits*)
((PEACH (500 PINK)) (APPLE (100 RED)) (BANANA (150 YELLOW)) (PEACH (300 PINK)))

;;; あたかも更新されてるみたいになる!
> (assoc 'peach *fruits*)
(PEACH (500 PINK))

更新されてるみたいになる。理解できた気がする!!

Land of Lispの説明文を引用

assocコマンドは常に、見つかった最初のエントリを返す。したがってpushコマンドを使うと、assocにとってはそのオブジェクトに対する場所が更新されたのと同じ効果を持つわけだ。pushとassocを使って、以前の値を残したまま、alistの値が変更されたかのように見せることができる。

参考文献

Land of Lisp

Land of Lisp