リストは順序なしの数学的集合 — リスト内に要素があれば集合の要素の値としてリスト内の順序は無視される —
を表すことができます。2つの集合を結合(union)するには、(重複する要素を気にしなければ)append
を使用します。equal
である重複を取り除くにはdelete-dups
やseq-uniq
を使用します。集合にたいする他の有用な関数にはmemq
やdelq
や、それらのequal
バージョンであるmember
とdelete
が含まれます。
Common Lispに関する注意: 集合を処理するためにCommon Lispには関数
union
(要素の重複がない)とintersection
がある。Emacs Lispではcl-libがこれらの変種を提供する。Lists as Sets in Common Lisp Extensionsを参照のこと。
この関数はobjectがlistのメンバーかどうかをテストする。メンバーならmemq
は、objectで最初に見つかった要素から開始されるリストをリターンする。メンバーでなければnil
をリターンする。memq
の文字‘q’は、この関数がobjectとリスト内の要素の比較にeq
を使用することを示す。たとえば:
(memq 'b '(a b c b a)) ⇒ (b c b a)
(memq '(2) '((1) (2))) ; 2つの(2)
がeq
である必要はない ⇒ 未定義;nil
か((2))
かも
この関数はlistからobjectとeq
であるような、すべての要素を破壊的に取り除いて結果のリストをリターンする。delq
の文字‘q’は、この関数がobjectとリスト内の要素の比較にeq
を使用することを示す(memq
やremq
と同様)。
delq
を呼び出すときは、通常は元のリストを保持していた変数にリターン値を割り当てて使用する必要がある(理由は以下参照)。
delq
関数がリストの先頭にある要素を削除する場合は、単にリストを読み進めてこの要素の後から開始される部分リストをリターンします。つまり:
(delq 'a '(a b c)) ≡ (cdr '(a b c))
リストの途中にある要素を削除するときは、必要なCDR (リストのCDRの変更を参照)を変更することで削除を行います。
(setq sample-list (list 'a 'b 'c '(4))) ⇒ (a b c (4))
(delq 'a sample-list) ⇒ (b c (4))
sample-list ⇒ (a b c (4))
(delq 'c sample-list) ⇒ (a b (4))
sample-list ⇒ (a b (4))
(delq 'a sample-list)
は何も取り除きませんが(単に短いリストをリターンする)、(delq 'c
sample-list)
は3番目の要素を取り除いてsample-list
を変更することに注意してください。引数listを保持するように形成された変数が、実行後にもっと少ない要素になるとか、元のリストを保持すると仮定しないでください!
かわりにdelq
の結果を保存して、それを使用してください。元のリストを保持していた変数に結果を書き戻すことはよく行なわれます。
(setq flowers (delq 'rose flowers))
以下の例では、delq
が比較しようとしている(list
4)
とsample-list
内の(4)
は、equal
ですがeq
ではありません:
(delq (list 4) sample-list) ⇒ (a c (4))
与えられた値とequal
な要素を削除したい場合には、delete
(以下参照)を使用してください。
この関数はobjectとeq
なすべての要素が除かれた、listのコピーをリターンする。remq
の文字‘q’は、この関数がobjectとリスト内の要素の比較にeq
を使用することを示す。
(setq sample-list (list 'a 'b 'c 'a 'b 'c)) ⇒ (a b c a b c)
(remq 'a sample-list) ⇒ (b c b c)
sample-list ⇒ (a b c a b c)
関数memql
はeql
(浮動小数点数の要素は値で比較される)を使用してメンバーとeql
を比較することにより、objectがlistのメンバーかどうかをテストする。objectがメンバーなら、memql
はlist内で最初に見つかった要素から始まるリスト、それ以外ならnil
をリターンする。
memq
と比較してみよう:
(memql 1.2 '(1.1 1.2 1.3)) ; 1.2
と1.2
はeql
。
⇒ (1.2 1.3)
(memq 1.2 '(1.1 1.2 1.3)) ; 2つの1.2
がeq
である必要はない ⇒ 未定義;nil
か(1.2 1.3)
かもしれない
以下の3つの関数はmemq
、delq
、remq
と似ていますが、要素の比較にeq
ではなくequal
を使用します。同等性のための述語を参照してください。
関数member
は、メンバーとobjectをequal
を使用して比較して、objectがlistのメンバーかどうかをテストする。objectがメンバーなら、member
はlistで最初に見つかったところから開始されるリスト、それ以外ならnil
をリターンする。
memq
と比較してみよう:
(member '(2) '((1) (2))) ; (2)
and (2)
are equal
.
⇒ ((2))
(memq '(2) '((1) (2))) ; 2つの(2)
がeq
である必要はない ⇒ 未定義;nil
か(2)
かもしれない
;; 同じ内容の2つの文字列はequal
(member "foo" '("foo" "bar"))
⇒ ("foo" "bar")
この関数はsequenceからobjectとequal
な要素を取り除いて、結果のシーケンスをリターンする。
sequenceがリストなら、delete
がdelq
に対応するように、member
はmemq
に対応する。つまりこの関数はmember
と同様、要素とobjectの比較にequal
を使用する。マッチする要素が見つかったら、delq
が行なうようにその要素を取り除く。delq
と同様、通常は元のリストを保持していた変数にリターン値を割り当てて使用する。
sequence
がベクターか文字列なら、delete
はobject
とequal
なすべての要素を取り除いたsequence
のコピーをリターンする。
たとえば:
(setq l (list '(2) '(1) '(2))) (delete '(2) l) ⇒ ((1)) l ⇒ ((2) (1)) ;;l
の変更に信頼性を要するときは ;;(setq l (delete '(2) l))
と記述する。
(setq l (list '(2) '(1) '(2)))
(delete '(1) l)
⇒ ((2) (2))
l
⇒ ((2) (2))
;; このケースではl
のセットの有無に違い
;; はないが他のケースに倣ってセットするべき
(delete '(2) [(2) (1) (2)]) ⇒ [(1)]
この関数はdelete
に対応する非破壊的な関数である。この関数はobject
とequal
な要素を取り除いた、sequence
(リスト、ベクター、文字列)のコピーをリターンする。たとえば:
(remove '(2) '((2) (1) (2))) ⇒ ((1))
(remove '(2) [(2) (1) (2)]) ⇒ [(1)]
Common Lispに関する注意: GNU Emacs Lispの関数
member
、delete
、remove
はCommon Lispではなく、Maclispを継承する。Common Lispでは比較にequal
を使用しない。
この関数はmember
と同様だが、objectが文字列でcaseとテキスト表現の違いを無視する。文字の大文字と小文字は等しいものとして扱われ、比較に先立ちユニバイト文字列はマルチバイト文字列に変換される。
この関数はlistからすべてのequal
な重複を破壊的に取り除いて、結果をlistに保管してそれをリターンする。list内の要素にequal
な要素がいくつかあるなら、delete-dups
は最初の要素を残す。非破壊的な操作についてはseq-uniq
を参照してください(シーケンスを参照)。
変数に格納されたリストへの要素の追加や、それを集合として使用する方法については、リスト変数の変更の関数add-to-list
も参照してください。