<jonrock@gmail.com> wrote:
+---------------
| I would like to find the entry in a list that maximizes a function.
| I started out with this:
| (defun find-maximizing-item (lst fun)
| (loop for item in lst
| maximizing (funcall fun item)))
| but that returns only the maximum value of the function and nothing
| about what entry in the list made that maximum value happen.
| Is there some other idiom I should be using instead?
+---------------
I don't know of one. AFAIK, one has to do it "manually", e.g.:
(defun find-maximizing-item (list &optional (function #'identity)
&key (test #'<))
(let ((max-item (first list))
(max-value (funcall function (first list)))
(max-position 0))
(loop for item in (rest list)
and position from 1
for value = (funcall function item)
when (funcall test max-value value)
do (setf max-item item
max-value value
max-position position))
(values max-item max-value max-position)))
I added MAX-POSITION 'cuz it might be useful sometimes
[but made it be the last value in the result, in case
you don't care]; uncrunched the Schemish variable names;
made the FUNCTION optional; added TEST [just for fun];
and unrolled the loop once to avoid calling FUNCTION
twice on the first item. Testing:
> (find-maximizing-item '(3 -4 2 5 -7 1 2))
5
5
3
> (find-maximizing-item '(3 -4 2 5 -7 1 2) (lambda (x) (* x x)))
-7
49
4
>
To make it more like other CL functions, you might want to make
the calling sequence use keyword KEY instead of a positional FUNCTION,
that is:
(defun find-maximizing-item (list &key (key #'identity) (test #'<))
(let ((max-item (first list))
(max-value (funcall key (first list)))
(max-position 0))
(loop for item in (rest list)
and position from 1
for value = (funcall key item)
when (funcall test max-value value)
do (setf max-item item
max-value value
max-position position))
(values max-item max-value max-position)))
> (find-maximizing-item '(3 -4 2 5 -7 1 2) :key (lambda (x) (* x x)))
-7
49
4
>
-Rob
p.s. I used #'< as the default :TEST [even though MAX-VALUE isn't an
input constant], because CLHS 17.2.1 "Satisfying a Two-Argument Test"
requires the list item being scanned to be the second argument of the
:TEST function.
-----
Rob Warnock <rpw3@rpw3.org>
627 26th Avenue <URL:http://rpw3.org/>
San Mateo, CA 94403 (650)572-2607