Skip to content
Snippets Groups Projects
Commit 8beef2dc authored by death's avatar death Committed by Michał Herda
Browse files

Use linear-time SHUFFLE if supplied with many list items to shuffle

parent f35e232c
No related branches found
No related tags found
No related merge requests found
...@@ -81,19 +81,28 @@ share structure with it." ...@@ -81,19 +81,28 @@ share structure with it."
(defun shuffle (sequence &key (start 0) end) (defun shuffle (sequence &key (start 0) end)
"Returns a random permutation of SEQUENCE bounded by START and END. "Returns a random permutation of SEQUENCE bounded by START and END.
Original sequence may be destructively modified, and (if it contains Original sequence may be destructively modified.
CONS or lists themselv) share storage with the original one.
Signals an error if SEQUENCE is not a proper sequence." Signals an error if SEQUENCE is not a proper sequence."
(declare (type fixnum start) (declare (type fixnum start)
(type (or fixnum null) end)) (type (or fixnum null) end))
(etypecase sequence (etypecase sequence
(list (list
(let* ((end (or end (proper-list-length sequence))) (let* ((end (or end (proper-list-length sequence)))
(n (- end start))) (n (- end start))
(do ((tail (nthcdr start sequence) (cdr tail))) (sublist (nthcdr start sequence))
((zerop n)) (small-enough-threshold 100))
(rotatef (car tail) (car (nthcdr (random n) tail))) ;; It's fine to use a pure list shuffle if the number of items
(decf n)))) ;; to shuffle is small enough, but otherwise it's more
;; time-efficient to create an intermediate vector to work on.
;; I picked the threshold based on rudimentary benchmarks on my
;; machine, where both branches take about the same time.
(if (< n small-enough-threshold)
(do ((tail sublist (cdr tail)))
((zerop n))
(rotatef (car tail) (car (nthcdr (random n) tail)))
(decf n))
(let ((intermediate-vector (replace (make-array n) sublist)))
(replace sublist (shuffle intermediate-vector))))))
(vector (vector
(let ((end (or end (length sequence)))) (let ((end (or end (length sequence))))
(loop for i from start below end (loop for i from start below end
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment