sort するには注意が必要
sort 関数を使ってみた。これは破壊的なようで、使い方を間違えるといろいろと問題を引き起こすことになりそうなのでメモ。
フラットなリストをsortする
並び換え対象のリストがフラットであれば、あまり難しいことはない。並び換えの前にコピーしておけば、もとの並び換え対象のオブジェクトに影響はないが、コピーしておかないと並び換え対象となったオブジェクト自体が変更されてしまう。まあ、これを期待することもあるかもしれないが。
? (defparameter x '(999 555 444 888 777 333 222 666 111)) X ? (sort (copy-list x) #'>) (999 888 777 666 555 444 333 222 111) ? x (999 555 444 888 777 333 222 666 111) ? (defparameter y "fwauhefojowfo") Y ? (sort y #'char-lessp) "aefffhjooouww" ? y "aefffhjooouww" ?
フラットじゃないリストをsortする
上でやったのと同じようにするだけではエラーになる。リスト内の要素一つ一つに並び換え条件で指定した処理を行うことができないといけないようだ。その場合は、:key で要素に対して何らかの処理を行うか、並び換え条件として渡す関数を作り込みしておく、ということになるだろうか。:key を使用した例は以下。
? (defparameter x '(("333" . "000") ("999" . "111") ("555" . "888"))) X ? (sort (copy-list x) #'string<) > Error: The value ("999" . "111") is not of the expected type (OR STRING SYMBOL CHARACTER). > While executing: STRING, in process listener(1). > Type :POP to abort, :R for a list of available restarts. > Type :? for other options. 1 > q ? (sort (copy-list x) #'string< :key #'car) (("333" . "000") ("555" . "888") ("999" . "111")) ? x (("333" . "000") ("999" . "111") ("555" . "888")) ? (sort (copy-list x) #'string< :key #'cdr) (("333" . "000") ("999" . "111") ("555" . "888")) ? x (("333" . "000") ("999" . "111") ("555" . "888")) ? (sort (copy-list x) #'string> :key #'cdr) (("555" . "888") ("999" . "111") ("333" . "000")) ? x (("333" . "000") ("999" . "111") ("555" . "888")) ?
string< でなく、独自の比較関数を渡すとかもできるはず。
関数を引数として渡すことができるということは?
関数を引数として渡すことができるというのはすごいかも。関数を引数として渡すことができない場合は、それだけで条件分岐しないといけなくてコード量が増える。値によって行う処理が違うというのは大抵はコードを書く時点でわかるはず。だったら、以下のように書かないで
public void function(String value){ if(value.equal("XXX"){ functionXXX(value); else { functionZZZ(value); } }
以下のように関数を定義して、
(defun function (value next-function) (funcall next-function value))
呼出側で
(function "XXX" #'functionXXX)
とか、
(function "AAA" #'functionAAA)
とかやればいい。でも、例がよくないかも。これじゃあまりメリットがわからないか。。。この応用方法はもっと堀り下げる必要がありそうだ。なんか革新的な書き方にできそうな気がするのだが。