From Newsgroup: comp.lang.lisp
Raffael Cavallaro wrote:
Indeed. Here's rob Warnock's version with the full boat of loop
keywords using triplets instead of an association list:
CL-USER 22 > (defun find-maximizing-item (list &key (key #'identity)
(test #'<))
(loop for item in list
for value = (funcall key item)
and position from 0
for current-triplet = (list item value position)
as max-triplet = current-triplet
then (if (funcall test (second max-triplet)
(second current-triplet))
current-triplet
max-triplet)
finally return
(values (first max-triplet) (second max-triplet)
(third max-triplet))))
Rejected by ABCL:
Debugger invoked on condition of type PROGRAM-ERROR:
Current LOOP context: "A compound form was expected, but ~S found.".
Rejected by SBCL:
; in: LAMBDA NIL
; (LOOP FOR ITEM IN LIST
; FOR VALUE = (FUNCALL KEY ITEM)
; AND POSITION FROM ...)
;
; caught ERROR:
; (in macroexpansion of (LOOP FOR ITEM ...))
; (hint: For more precise location, try *BREAK-ON-SIGNALS*.)
; A compound form was expected, but RETURN found.
; current LOOP context: FINALLY RETURN (VALUES (FIRST MAX-TRIPLET)
; (SECOND MAX-TRIPLET)
; (THIRD MAX-TRIPLET)).
FIND-MAXIMIZING-ITEM
CL-USER 28 > (find-maximizing-item (list "one" "two" "three" "fifteen" "four" "five") :key #'length)
"fifteen"
7
3
It's somewhat shorter in Gauche Scheme.
(use gauche.collection) ;; find-max
(define (find-maximizing-item items :optional (key identity))
(find-max
(map (lambda (x i) (list x (key x) i)) items (liota))
:key cadr))
(find-maximizing-item (list "one" "two" "three" "fifteen" "four"
"five") string-length)
===>
("fifteen" 7 3)
--- Synchronet 3.21d-Linux NewsLink 1.2