From sketerpot at gmail.com Fri May 13 20:50:35 2005 From: sketerpot at gmail.com (Peter Scott) Date: Fri, 13 May 2005 14:50:35 -0600 Subject: [cl-utilities-devel] Idea: EXTREMA function Message-ID: <7e267a920505131350636c1d2e@mail.gmail.com> The EXTREMUM function returns the smallest element of a sequence, as determined by a binary comparison function such as #'<. A similar thing that could be useful is a way of returning the n smallest elements of a list (or possibly a proper sequence), determined in the same way. This can be done very nicely with an insertion sort, but that is either destructive or conses a lot. Having destructive and nondestructive versions has been proposed, and I think it's a good idea. So, here are a couple of implementations: (defun nextrema (list predicate n &key (key #'identity)) (declare (optimize (speed 3) (safety 0)) (list list) (unsigned-byte n)) (loop for itail on list for i from 0 while (< i n) do (loop for jtail on itail do (if (funcall predicate (funcall key (car jtail)) (funcall key (car itail))) (rotatef (car jtail) (car itail))))) (subseq list 0 n)) (defun extrema (list predicate n &key (key #'identity)) (declare (optimize (speed 3) (safety 0)) (list list) (unsigned-byte n)) (collecting (let* ((unsorted-part list)) (loop repeat (min n (length list)) do (let ((smallest (extremum unsorted-part predicate :key key))) (collect smallest) (setf unsorted-part (remove smallest unsorted-part))))))) Notice that these don't take START and END keyword arguments; this is because I was too lazy to add them to proof-of-concept code. What these do is perform a partial insertion sort on LIST and return the sorted part. As you'd expect, the destructive version is faster than the nondestructive version. However, these implementations are probably far from optimal. Here's another version which you may find interesting: (defun naive-extrema (list predicate n &key (key #'identity)) (subseq (sort list predicate :key key) 0 n)) This is the best version yet, since it works on all proper sequences and is faster than either of the two versions that I made. Amazing how much effort is put into the SORT function, isn't it? -Peter