ド素人が始めるCommon Lisp 11. リストでテーブルを扱う

Common Lisp ド素人

前回、前々回とリストに対する関数、集合として扱う際の関数を学んできた。今回はリストをテーブルとして扱っていく。
前回の記事はこちら。

Contents

この記事に出てくる関数一覧

function description
assoc key入力に対して該当するvalueを返す
rassoc

リストをテーブルとして扱う

例として以下のテーブルを考えてみる。

key a b c d
value Hokkaido Honshu Shikoku Kyushu

これをリストで以下のように表す。

(setf sample-table (list '(a "Hokkaido")
                         '(b "Honshu")
                         '(c "Shikoku")
                         '(d "Kyushu")))

これに対してaに対応するHokkaidoを探し出すことが最もシンプルな形だろう。

assoc: keyから要素を返す

assocを使うことでkeyに該当する要素を得ることができる。
基本の形

(assoc key alist)

実際に上のテーブルに試してみよう。

(assoc 'a sample-table) ; => (A "Hokkaido")
(assoc 'b sample-table) ; => (B "Honshu")
(assoc 'c sample-table) ; => (C "Shikoku")
(assoc 'd sample-table) ; => (D "Kyushu")
(assoc 'e sample-table) ; => NIL
(assoc "Hokkaido" sample-table) ; => NIL

このように対応する対が返されるのでkeyに対応するvalueそのもの(例の場合aに対する"Hokkaido")が欲しい場合はさらにsecondを適用する必要がある。

また基本の形のなかでalistと書いているがこれはassociation listのことである。またplist(parameter list)というものもある。

rassoc: valueから要素を返す

rassocを使うことでassocとは逆にvalueから該当する要素を得ることができる。
基本の形

(rassoc key alist)

ただしrassocの場合は要素がリストではなくドット対でなければならない。つまり上記で使ったテーブルに代わり以下のものを用意する。

(setf sample-table-dot (list '(a . hokkaido)
                             '(b . honshu)
                             '(c . shikoku)
                             '(d . kyushu)))
; => ((A . HOKKAIDO) (B . HONSHU) (C . SHIKOKU) (D . KYUSHU))

このリストにrassocを使ってみよう。

(rassoc 'hokkaido sample-table-dot) ; => (A . HOKKAIDO)
(rassoc 'honshu sample-table-dot)   ; => (B . HONSHU)
(rassoc 'shikoku sample-table-dot)  ; => (C . SHIKOKU)
(rassoc 'kyushu sample-table-dot)   ; => (D . KYUSHU)
(rassoc 'okinawa sample-table-dot)  ; => NIL
(rassoc 'a sample-table-dot)    ; => NIL

assocと逆の検索ができていることがわかるだろう。
ちなみにドット対にassocを使用することはできる。

(assoc 'a sample-table-dot) ; => (A . HOKKAIDO)

比較に使われるオペレータ

上記の例でrassoc用に用意したドット対では文字列ではなくシンボルを使用している。なぜかというと文字列だとrassocそのまま使用した場合にうまく値が返ってこない。
以下に実例を示す。

(setf sample-table-dot-2 (list '(a . "Hokkaido")
                               '(b . "Honshu")
                               '(c . "Shikoku")
                               '(d . "Kyushu")))
; => ((A . "Hokkaido") (B . "Honshu") (C . "Shikoku") (D . "Kyushu"))

(rassoc "Hokkaido" sample-table-dot-2)  ; => NIL

これは比較のために使われるデフォルトのオペレータによって引き起こされている。assoc, rassocともに比較に使うオペレータを指定することができ、それをequalにすると期待した動きにはなる。

(rassoc "Hokkaido" sample-table-dot-2 :test #'equal)    ; => (A . "Hokkaido")

コロンで始まるキーワードについてはまた別の機会に記事にしたいと思うがそれを用いて比較用のオペレータをequalに指定すると対応する要素を取り出せていることがわかるだろう。
これは集合ででてきたmember等でも同じことがいえる。等価であることを調べるオペレータはたくさんあるのでその違いもいずれ別の記事にしたい。

まとめ

3回続けてリストをいじる記事を書いてきた。まだまだ完全に自分のもににはできていないが引き続き慣れていきたい。

  • appendでリスト同士を連結できる
  • reverseでリストを逆順にできる
  • nth, nthcdrcar,cdr,cadr,cddr...を一般化できる
  • lastでリストの最後の要素を得る
  • removeでリストの要素を削除する
  • リストを集合として扱うこともできる
    • memberで要素を調べる
    • intersectionで積集合
    • unionで和集合
    • sub-differenceで差集合
    • subsetpで部分集合かどうかを調べる
    • adjoinで要素追加
  • リストをテーブルとして扱うこともできる
    • assoc、rassocでテーブル検索できる

ここまでで扱いきれなかった内容として以下がある。これらもいずれ記事としたい。

  • リスト演算の効率
  • 等価を評価する種々のオペレータ
  • plist
  • ハッシュテーブル
  • リストを用いたtree構造
  • キーワード

コメント

タイトルとURLをコピーしました