要素から最大/最小のものを取得したい
Lisp には、渡されたパラメータの中から最大のものを返すmaxと最小のものを返す min という関数がある。
? (max 10 11 12 13 14 15) 15 ? (min 10 11 12 13 14 15) 10 ?
しかし、これは引数がlistになると動作しない。
? (max '(10 11 12 13 14 15)) > Error: The value (10 11 12 13 14 15) is not of the expected type REAL. > While executing: MAX, in process Listener(4). > Type cmd-. to abort, cmd-\ for a list of available restarts. > Type :? for other options. 1 > q ? (min '(10 11 12 13 14 15)) > Error: The value (10 11 12 13 14 15) is not of the expected type REAL. > While executing: MIN, in process Listener(4). > Type cmd-. to abort, cmd-\ for a list of available restarts. > Type :? for other options. 1 > q ?
なんか設計間違えてないか?と思うが。Common Lisp HyperSpec (TM)の中から、該当しそうなものを探してみたが特定できなかった(あるのかもしれないが見つけられなかった)ので書いてみた。
(defun max-number (l) (when (listp l) (let ((x (car l))) (dolist (n (cdr l)) (setf x (max x n))) x))) (defun min-number (l) (when (listp l) (let ((x (car l))) (dolist (n (cdr l)) (setf x (min x n))) x)))
ここから dolist を排除。
(defun max-number (l) (labels ((comp (n l) (if (null l) n (comp (max n (car l)) (cdr l))))) (when (listp l) (comp (car l) (cdr l))))) (defun min-number (l) (labels ((comp (n l) (if (null l) n (comp (min n (car l)) (cdr l))))) (when (listp l) (comp (car l) (cdr l)))))
これは両方似ているので重複分をまとめる。
(defun select-if (l condition) (labels ((compare (n l) (if (null l) n (compare (funcall condition n (car l)) (cdr l))))) (when (listp l) (compare (car l) (cdr l))))) (defun max-number (l) (select-if l #'max)) (defun min-number (l) (select-if l #'min))
以下、実行結果。想定通りに動作していそうだ。
? (let ((n (get-random-list 10))) (format t "Original List is ~A, Min is ~A, Max is ~A~%" n (min-number n) (max-number n))) Original List is (78 27 80 61 70 49 17 32 26 60), Min is 17, Max is 80 NIL ? (let ((n (get-random-list 10))) (format t "Original List is ~A, Min is ~A, Max is ~A~%" n (min-number n) (max-number n))) Original List is (30 67 25 100 6 29 13 32 80 75), Min is 6, Max is 100 NIL ? (let ((n (get-random-list 10))) (format t "Original List is ~A, Min is ~A, Max is ~A~%" n (min-number n) (max-number n))) Original List is (91 5 93 83 35 38 81 84 30 4), Min is 4, Max is 93 NIL ?