リストは順序のない数学的集合を表現できます—単に、リストに出現する値を集合の要素と見なし、リストの順序は無視すればよいのです。2つの集合の和集合を作成するには、append を使用します(要素の重複を気にしない場合に限ります)。equal の重複は、delete-dups または
seq-uniq を使って削除できます。集合に関するその他の便利な関数には、memq や delq、およびそれらの equal 版である member や delete があります。
Common Lispに関する注記: Common Lispには、集合操作用の関数
union(重複要素を排除する)とintersectionがあります。Emacs Lispでは、これらの機能のバリエーションが cl-lib ライブラリによって提供されています。Common Lisp Extensions の Lists as Sets を参照してください。
この関数は、object が list
の要素であるかどうかを判定します。要素である場合、memq は object の最初の出現箇所から始まるリストを返します。そうでない場合は、nil を返します。memq 内の文字
‘q’ は、object
をリストの要素と比較する際に eq を使用することを示しています。例えば:
(memq 'b '(a b c b a))
⇒ (b c b a)
(memq '(2) '((1) (2))) ; The two(2)s need not beeq. ⇒ Unspecified; might benilor((2)).
この関数は、list から eq から object までのすべての要素を破壊的に削除し、得られたリストを返します。delq 内の文字 ‘q’
は、eq を用いて object を 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 'c sample-list) は sample-list を変更して3番目の要素を切り出しますが、(delq
'a 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 を使用してください(以下を参照)。
この関数は、list のコピーから、eq から
object までのすべての要素を除去して返します。remq 内の文字 ‘q’
は、object を list の要素と比較する際に
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 は、object が list の要素であるかどうかを判定し、eql を用いて要素を
object と比較するため、浮動小数点要素は値で比較されます。object が要素である場合、memql は list における最初の出現箇所から始まるリストを返します。そうでない場合は、nil を返します。
これを memq と比較してください:
(memql 1.2 '(1.1 1.2 1.3)) ; 1.2 and 1.2 are eql.
⇒ (1.2 1.3)
(memq 1.2 '(1.1 1.2 1.3)) ; The two1.2s need not beeq. ⇒ Unspecified; might benilor(1.2 1.3).
以下の3つの関数はmemq、delq、remqと同様ですが、要素の比較にeqではなくequalを使用します。等価述語を参照してください。
関数 member は、object が list の要素であるかどうかを判定し、equal
を用いて要素を object と比較します。object
が要素である場合、member は list
における最初の出現箇所から始まるリストを返します。そうでない場合は、nil を返します。
これを memq と比較してください:
(member '(2) '((1) (2))) ; (2) and (2) are equal.
⇒ ((2))
(memq '(2) '((1) (2))) ; The two(2)s need not beeq. ⇒ Unspecified; might benilor(2).
;; Two strings with the same contents are equal.
(member "foo" '("foo" "bar"))
⇒ ("foo" "bar")
この関数は、sequence から equal から
object までのすべての要素を削除し、得られた数列を返します。
sequence がリストである場合、delete と
delq の関係は、member と memq の関係と同様です。つまり、member のように
equal を用いて要素を object
と比較し、一致する要素が見つかると、delq と同様にその要素を切り出します。delq の場合と同様に、通常は戻り値を元のリストを保持していた変数に代入して使用します。
sequence がベクトルまたは文字列の場合、delete は sequence からすべての要素
equal ~ object
を削除したコピーを返します。
例えば:
(setq l (list '(2) '(1) '(2)))
(delete '(2) l)
⇒ ((1))
l
⇒ ((2) (1))
;; If you want to change l reliably,
;; write (setq l (delete '(2) l)).
(setq l (list '(2) '(1) '(2)))
(delete '(1) l)
⇒ ((2) (2))
l
⇒ ((2) (2))
;; In this case, it makes no difference whether you set l,
;; but you should do so for the sake of the other case.
(delete '(2) [(2) (1) (2)])
⇒ [(1)]
この関数は、delete の非破壊版です。リスト、ベクトル、または文字列である sequence から、要素 equal から object を取り除いたコピーを返します。例えば:
(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
は文字列である必要があり、また大文字・小文字の区別やテキスト表現の違いを無視する点が異なります。大文字と小文字は等価に扱われ、ユニバイト文字列は比較前にマルチバイトに変換されます。
この関数は、list からすべての equal
の重複を破壊的に削除し、その結果を list に格納して返します。list 内に要素が equal 回出現する場合、delete-dups は最初の1つを保持します。非破壊的な操作については seq-uniq を参照してください(シーケンス を参照)。
変数に格納され、集合として使用されるリストに要素を追加する方法については、リスト変数の変更にある関数 add-to-list も参照してください。