名前の末尾に「Jr.」や「MD」というサフィックスが付いているときに、それを無視してラストネームを抽出するプログラムを書け、というもの。
;;; Exercise 1.1 (defparameter *suffixes* '(MD Jr Sr II III) "A list of suffixes that can appear at the end of a name.") (defun last-name (name) "Select the last name from a name represented as a list." (if (member (first (last name)) *suffixes*) (last-name (reverse (rest (reverse name)))) (first (last name)))) (mapcar #'last-name '((Rex Morgan MD) (Morton Downey Jr)))
文中のfirst-nameを参考にして単純にやってみたけど、reverseが何回も出てくるのが気持ち悪い。リストの最後から順番に見る良い方法はないだろうか。
リストの前方から見ていって、「見ている要素の次の要素が*suffixes*に含まれていたら、いま見ている要素がラストネーム」というやり方もあるなぁ、と書き直したのが以下。
(defun last-name (name) "Select the last name from a name represented as a list." (if (or (null (rest name)) (member (first (rest name)) *suffixes*)) (first name) (last-name (rest name))))
(null (rest name))をチェックしないと、(last-name '(first last))というサフィックス無しの名前を入れたら無限ループに陥ってびっくりしますよ。他にも何かバグが潜んでいそうな気がするプログラムです。
そのほか考えられるケースも想定してプログラムを適宜変更せよ、という問題なので、(First Last, Ph.D.)という場合を試してみたら、「クォートされたリスト中にコンマは入れられませんよ」とエラーが出ましたとさ。