Next: 10 例題: データベース検索例
Up: 9 シーケンスデータ
Previous: 9.9 find-all-if
findはひとつのデータを見つけ出すという関数でしたが,
find-allという関数はあるデータと比較して関連するデータを
すべて見つけ出す関数とします.
CommonLispにはありませんが,以下にそれを定義します.
<cl> (find-all 3 '(2 -3.0 1 2 3 -3 4 5))
(3)
<cl> (find-all 3 '(2 -3.0 1 2 3 -3 4 5) :key #'abs)
(3 -3)
<cl> (find-all 3 '(2 -3.0 1 2 3 -3 4 5) :key #'abs
:test #'equalp)
(-3.0 3 -3)
この関数find-allを作るためにはremoveを使うことができます.
<cl> (remove 3 '(2 -3.0 1 2 3 -3 4 5))
(2 -3.0 1 2 -3 4 5)
<cl> (remove 3 '(2 -3.0 1 2 3 -3 4 5) :test #'equalp)
(2 -3.0 1 2 -3 4 5)
<cl> (remove 3 '(2 -3.0 1 2 3 -3 4 5)
:key #'abs :test #'equalp)
(2 1 2 4 5)
<cl> (remove 3 '(2 -3.0 1 2 3 -3 4 5) :key #'abs
:test #'(lambda (x y) (not (equalp x y))))
(-3.0 3 -3)
以下のようにfind-allを定義することができます.
(defun find-all (item sequence
&rest keyword-args
&key (test #'eql)
&allow-other-keys)
(apply #'remove item sequence
:test #'(lambda (&rest args)
(not (apply test args)))
keyword-args))
ここで,&allow-other-keysというのは&keyによってキーワード引数として
宣言されている:test以外のキーワードを受け付けるためにつけなければ
ならないものです.
(find-all 3 '(2 -3.0 1 2 3 -3 4 5)
:key #'abs :test #'equalp)
とした場合には,&rest引数である keyword-argsには
(:key #'abs :test #'equalp)
が入っています.このkeyword-argsがapplyによってそのままremoveの引数として
渡されてしまいます.つまり,
(apply #'remove 3 '(2 -3.0 1 2 3 -3 4 5)
:test #'(lambda (&rest args)
(not (apply #'equalp args)))
(list :key #'abs :test #'equalp))
となって渡されたことになり,結局,
(remove 3 '(2 -3.0 1 2 3 -3 4 5)
:test #'(lambda (&rest args)
(not (apply #'equalp args)))
:key #'abs :test #'equalp)
と実行したことと同じになります.ここで,:testのキーワードが二つ渡され
たことになりますが,最初のキーワードが優先されるようになっています.
<cl> (apply #'remove 3 '(2 -3.0 1 2 3 -3 4 5)
:test #'(lambda (&rest args)
(not (apply #'equalp args)))
(list :key #'abs :test #'equalp))
(-3.0 3 -3)
<cl> (remove 3 '(2 -3.0 1 2 3 -3 4 5)
:test #'(lambda (&rest args)
(not (apply #'equalp args)))
:key #'abs :test #'equalp)
(-3.0 3 -3)
removeはシーケンスデータに対応した関数になっているため,find-allもシー
ケンスデータに対応しています.しかし,シーケンスでない一般のリストデー
タには適用できません.
<cl> (find-all #\3 "123456343")
"333"
<cl> (find-all 3 '(2 -3.0 1 2 (3) -3 4 5)
:key #'abs :test #'equalp)
Error: non-number to abs: (3)
<cl> (find-all 3 '(2 -3.0 1 2 (3) -3 4 5)
:test #'equalp)
NIL
generated through LaTeX2HTML. M.Inaba 平成18年5月7日