(defparameter *implementations* (list ;; ideone.com/g6m1EK (defun find-second-smallest-number-r1 (list) (loop for n in list for second = n then (if (< first n second) n second) minimize n into first finally (return (if (> second first) second nil)))) (defun find-second-smallest-number-r2-UNIQ-AND-SORT (list) (let ((result (if (null list) nil (nth 1 (sort (remove-duplicates list) #'<))))) ;; sort 函数によって比較函数 < が適用されることで、数以外を含む ;; ときはエラーとなることを期待したが、要素が一つだけのときは比 ;; 較されないためエラーも起きない。 (when (and (eq result nil) (not (null list)) (not (subtypep (type-of (first list)) 'real))) (error 'type-error :expected-type 'real :datum (first list))) result)) (defun find-second-smallest-number-r3 (list) (when (eq (nth 1 list) nil) ;; (nth 1 list) の値が nil のとき、LIST は空リストであるか、要 ;; 素数が 1 であるか、または先頭から二つ目の要素が nil である。 ;; このとき LIST の要素に大小比較可能な数以外の要素が含まれる場 ;; 合はコンディション type-error を送出する。 (loop for x in list unless (subtypep (type-of x) 'real) do (error 'type-error :expected-type 'real :datum x))) (loop for n in list for 2nd = nil then (if (= n 1st) 2nd (if (null 2nd) (max n 1st) (if (< n 1st) (max n 1st) (min n 2nd)))) minimize n into 1st finally (return 2nd))))) (defparameter *test-cases* (let ((N 100000) (type-error (make-condition 'type-error :datum nil :expected-type t))) `(((4 5 1 7 1 2 8 9 2 7) 2) ((2 2 2 2 2 2 2 2 2 2) nil) ((1) nil) ((2 1) 2) ((1 2) 2) ((3 2 1) 2) ((1/2 1/3 1/42) 1/3) ((,pi 3.14) ,pi) ((3.141592653589793d0 ,(log #c(-1 0))) ,type-error) ((0) nil) (() nil) ((t) ,type-error) ((1 nil) ,type-error) ((1 2 3 nil) ,type-error) (,(cons 2 (make-list N :initial-element 1)) 2) (,(cons 2 (make-list N :initial-element nil)) ,type-error)))) (defun run-tests (fn test-cases &optional (detailed-output-p t)) (flet ((test (expected result) (if (and detailed-output-p (subtypep (type-of expected) 'condition)) (subtypep (type-of result) (type-of expected)) (eql result expected)))) (loop with *print-length* = 10 with *print-right-margin* = 5000 for (arg expected) in test-cases for result = (handler-case (funcall fn arg) (error (condition) (if detailed-output-p condition (class-name (class-of condition))))) for all-tests-passed-p = (test expected result) then (and all-tests-passed-p (test expected result)) do (format t (if detailed-output-p "~:[❌~;✓~] ~:S → ~S~%" "~*~:S → ~A~%") (test expected result) arg result) finally (return all-tests-passed-p)))) (defun make-string-sink () (make-array 0 :element-type 'character :fill-pointer 0 :adjustable t)) (defun clear-string-sink (sink) (setf (fill-pointer sink) 0)) (let ((debug nil)) (let ((fn (car (last *implementations*)))) (run-tests fn *test-cases* nil)) (format t "~%~50@{=~}~2%" t) (let ((tests-output (make-string-sink)) all-tests-passed-p) (dolist (fn *implementations*) #+clisp (format t "~2%") (format t "Testing ‘~(~A~)’... " fn) (with-output-to-string (*standard-output* tests-output) (setq all-tests-passed-p (run-tests fn *test-cases*))) (format t "~:[FAILED~;OK~]~%" all-tests-passed-p) (if all-tests-passed-p ;; テストを通過したら速度も計測。 (time (loop repeat 100000 do (funcall fn (caar *test-cases*)))) (if debug (write-line tests-output) (terpri))) (clear-string-sink tests-output))))
Standard input is empty
(4 5 1 7 1 2 8 9 2 7) → 2 (2 2 2 2 2 2 2 2 2 2) → NIL (1) → NIL (2 1) → 2 (1 2) → 2 (3 2 1) → 2 (1/2 1/3 1/42) → 1/3 (3.1415926535897932385L0 3.14) → 3.1415926535897932385L0 (3.141592653589793d0 #C(0 3.1415927)) → SIMPLE-TYPE-ERROR (0) → NIL () → NIL (T) → TYPE-ERROR (1 NIL) → TYPE-ERROR (1 2 3 NIL) → SIMPLE-TYPE-ERROR (2 1 1 1 1 1 1 1 1 1 ...) → 2 (2 NIL NIL NIL NIL NIL NIL NIL NIL NIL ...) → TYPE-ERROR ================================================== Testing ‘find-second-smallest-number-r1’... FAILED Testing ‘find-second-smallest-number-r2-uniq-and-sort’... OK Real time: 0.945274 sec. Run time: 0.938306 sec. Space: 6409240 Bytes GC: 4, GC time: 0.017972 sec. Testing ‘find-second-smallest-number-r3’... OK Real time: 2.616 sec. Run time: 2.598114 sec. Space: 9144 Bytes
Warning: reserving address range 0x80000c0000...0x1fffffffffff that contains memory mappings. clisp might crash later! Memory dump: 0x8000000000 - 0x80000bffff 0x146e22200000 - 0x146e224e4fff 0x146e22615000 - 0x146e22639fff 0x146e2263a000 - 0x146e227acfff 0x146e227ad000 - 0x146e227f5fff 0x146e227f6000 - 0x146e227f8fff 0x146e227f9000 - 0x146e227fbfff 0x146e227fc000 - 0x146e227fffff 0x146e22800000 - 0x146e22802fff 0x146e22803000 - 0x146e22a01fff 0x146e22a02000 - 0x146e22a02fff 0x146e22a03000 - 0x146e22a03fff 0x146e22a80000 - 0x146e22a8ffff 0x146e22a90000 - 0x146e22ac3fff 0x146e22ac4000 - 0x146e22bfafff 0x146e22bfb000 - 0x146e22bfbfff 0x146e22bfc000 - 0x146e22bfefff 0x146e22bff000 - 0x146e22bfffff 0x146e22c00000 - 0x146e22c03fff 0x146e22c04000 - 0x146e22e03fff 0x146e22e04000 - 0x146e22e04fff 0x146e22e05000 - 0x146e22e05fff 0x146e22e30000 - 0x146e22e33fff 0x146e22e34000 - 0x146e22e34fff 0x146e22e35000 - 0x146e22e36fff 0x146e22e37000 - 0x146e22e37fff 0x146e22e38000 - 0x146e22e38fff 0x146e22e39000 - 0x146e22e39fff 0x146e22e3a000 - 0x146e22e47fff 0x146e22e48000 - 0x146e22e55fff 0x146e22e56000 - 0x146e22e62fff 0x146e22e63000 - 0x146e22e66fff 0x146e22e67000 - 0x146e22e67fff 0x146e22e68000 - 0x146e22e68fff 0x146e22e69000 - 0x146e22e6efff 0x146e22e6f000 - 0x146e22e70fff 0x146e22e71000 - 0x146e22e71fff 0x146e22e72000 - 0x146e22e72fff 0x146e22e73000 - 0x146e22e73fff 0x146e22e74000 - 0x146e22ea1fff 0x146e22ea2000 - 0x146e22eb0fff 0x146e22eb1000 - 0x146e22f56fff 0x146e22f57000 - 0x146e22fedfff 0x146e22fee000 - 0x146e22feefff 0x146e22fef000 - 0x146e22feffff 0x146e22ff0000 - 0x146e23003fff 0x146e23004000 - 0x146e2302bfff 0x146e2302c000 - 0x146e23035fff 0x146e23036000 - 0x146e23037fff 0x146e23038000 - 0x146e2303dfff 0x146e2303e000 - 0x146e23040fff 0x146e23043000 - 0x146e23043fff 0x146e23044000 - 0x146e23044fff 0x146e23045000 - 0x146e23045fff 0x146e23046000 - 0x146e23046fff 0x146e23047000 - 0x146e23047fff 0x146e23048000 - 0x146e2304efff 0x146e2304f000 - 0x146e23051fff 0x146e23052000 - 0x146e23052fff 0x146e23053000 - 0x146e23073fff 0x146e23074000 - 0x146e2307bfff 0x146e2307c000 - 0x146e2307cfff 0x146e2307d000 - 0x146e2307dfff 0x146e2307e000 - 0x146e2307efff 0x561bc52c8000 - 0x561bc53b8fff 0x561bc53b9000 - 0x561bc54c2fff 0x561bc54c3000 - 0x561bc5522fff 0x561bc5524000 - 0x561bc5552fff 0x561bc5553000 - 0x561bc5583fff 0x561bc5584000 - 0x561bc5587fff 0x561bc642d000 - 0x561bc644dfff 0x7ffc0ea45000 - 0x7ffc0ea65fff 0x7ffc0ea8d000 - 0x7ffc0ea90fff 0x7ffc0ea91000 - 0x7ffc0ea92fff