Here is an existing "sampling" clause to pull a random sample from a
larger data set. The long and short is just use a finally clause, as
you would when writing a normal iterate loop.
(iterate:defmacro-clause (sampling expr &optional into var size size)
"resevoir sample the input"
(let ((sample (or var iterate::*result-var*)))
(alexandria:with-unique-names (i sample-size sigil buffer row)
`(progn
(with ,sample)
(with ,sample-size = (or ,size 100))
(with ,buffer = (make-array ,sample-size :initial-element ',sigil))
(with ,i = 0)
(if (< ,i ,sample-size)
(setf (aref ,buffer ,i) ,expr)
(let ((r (random ,i)))
(when (< r ,sample-size)
(setf (aref ,buffer r) ,expr))))
(incf ,i)
(finally
;; convert our sample to a list, but only if we actually took
the sample
(when (plusp ,i)
(setf ,sample
(iter (for ,row in-vector ,buffer)
(until (eq ,row ',sigil))
(collect ,row)))))))))
Cheers,
Russ Tyndall
Acceleration.net
On 03/13/2018 10:49 AM, Robert Goldman wrote:
I was going to define an |AVERAGING| collector clause for iterate, but
I'm not sure how to do it. The obvious thing, it seemed to me, would
be to sum the values as I go along, and count them, and then divide
the sum by the count when leaving the loop.
But the examples for |DEFMACRO-CLAUSE| in the manual do all of their
work while iterating, and there doesn't seem to be an "at-end" hook.
Is the kind of thing I would like feasible, and if so, how is it to be
done?
thanks!
r