Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a more idiomatic way to get N random elements of a collection in Clojure?

Tags:

idioms

clojure

I’m currrently doing this: (repeatedly n #(rand-nth (seq coll))) but I suspect there might be a more idiomatic way, for 2 reasons:

  • I’ve found that there’s frequently a more concise and expressive alternative to using short anonymous functions, e.g. partial
  • the docstring for repeatedly says “presumably with side effects”, implying that it’s not intended to be used to produce values

I suppose I could figure out a way to use reduce but that seems like it would be tricky and less efficient, as it would have to process the entire collection, since reduce is not lazy.

like image 234
Avi Flax Avatar asked Mar 22 '23 17:03

Avi Flax


2 Answers

An easy solution but not optimal for big collections could be:

(take n (shuffle coll))

Has the "advantage" of not repeating elements. Also you could implement a lazy-shuffle but it will involve more code.

like image 64
barracel Avatar answered Apr 26 '23 20:04

barracel


I know it's not exactly what you're asking - but if you're doing a lot of sampling and statistical work, you might be interested in Incanter ([incanter "1.5.2"]). Incanter provides the function sample, which provides options for sample size, and replacement.

(require '[incanter.stats :refer [sample]]))

(sample [1 2 3 4 5 6 7] :size 5 :replacement false) 
; => (1 5 6 2 7)
like image 42
Daniel Neal Avatar answered Apr 26 '23 20:04

Daniel Neal