and $y$ are considered equal if and only if @|(funcall @<test> (funcall
@<key> $x$) (funcall @<key> $y$))| returns non-nil.
+ The @<report> function is called as @|(funcall @<report> @<duplicate>
+ @<previous>)|. Duplicates are reported in order; the @<previous> item is
+ always the first matching item in the sequence.
+
This function will work for arbitrary @<test> functions, but it will run
- much more efficiently if @<test> is @|eq|, @|eql|, @|equal|, or @|equalp|
- (because it can use hash-tables).
+ much more efficiently if @<test> is @|eq|, @|eql|, @|equal|, or @|equalp|,
+ because it can use hash-tables. (The generic implementation for lists is
+ especially inefficient.)
\end{describe}
(setf (gethash k seen) item)))))
sequence)))
((listp sequence)
- (mapl (lambda (tail)
- (let* ((item (car tail))
- (rest (cdr tail))
- (match (member (funcall key item) rest
- :test test :key key)))
- (when match (funcall report item (car match)))))
- sequence))
+ (do ((tail sequence (cdr tail))
+ (i 0 (1+ i)))
+ ((endp tail))
+ (let* ((item (car tail))
+ (match (find (funcall key item) sequence
+ :test test :key key :end i)))
+ (when match (funcall report item match)))))
((vectorp sequence)
(dotimes (i (length sequence))
(let* ((item (aref sequence i))
(pos (position (funcall key item) sequence
- :key key :test test :start (1+ i))))
+ :key key :test test :end i)))
(when pos (funcall report item (aref sequence pos))))))
(t
(error 'type-error :datum sequence :expected-type 'sequence))))