Fork me on GitHub
#beginners
<
2024-04-05
>
Sam Ferrell18:04:02

Any suggestions on how I might make a lazy infinite (or representable as a transducer) version of this function such that it can be parameterless? I'm not super familiar with crafting lazy seqs.

(defn random-nums
  "Returns a collection of random integers in the domain of [1, 20]. The first
   20 are guaranteed to be unique among each other, as well as the next 20,
   and so on. Only returns the first x integers."
  [x]
  (->> (range 1 21)
       (repeat (ceil (/ x 20)))
       (sequence (comp (map shuffle) cat (take x)))))

phronmophobic18:04:28

I would probably do something like:

(defn random-nums
  "Returns a collection of random integers in the domain of [1, 20]. The first
   20 are guaranteed to be unique among each other, as well as the next 20,
   and so on. Only returns the first x integers."
  []
  (eduction
   (mapcat (fn [[start end]]
             (shuffle (range start end))))
   (repeat [1 21])))

> (take 25 (random-nums))
(11 20 4 17 6 14 5 15 8 1 2 12 7 13 16 10 18 3 19 9 13 15 17 8 9)

Sam Ferrell18:04:40

Ahh thats it, I was almost there laughcry thanks a bunch!

Ed19:04:52

eduction won't return a lazy-seq. which can lead to situations like

(let [x (random-nums)]
    [(first x) (first x)]) ;; => [6 16]
You might prefer sequence when applying the transducer
(defn random-nums []
  (->> (repeat (range 1 21))
       (sequence (comp (map shuffle) cat))))

👍 1
phronmophobic19:04:47

you can always do (sequence (random-nums))

👍 1
adi11:04:30

Another way to express the same thing...

(def one-to-20 (range 1 21))

(defn rand-20s [n]
  (take n (mapcat identity
            (repeatedly #(shuffle one-to-20)))))

user=> (rand-20s 20)
(10 3 2 5 14 1 9 20 15 16 13 19 7 17 4 12 6 11 18 8)

user=> (rand-20s 20)
(11 1 6 10 14 5 4 19 16 3 12 8 7 15 9 13 18 17 2 20)

user=> (rand-20s 20)
(20 4 3 5 13 14 6 19 17 11 7 10 18 2 15 9 12 16 8 1)

john13:04:14

Yeah, looks like this example is too small for transducers to really make a difference

john13:04:32

Maybe uses less memory

john14:04:01

well, maybe 20 or 25% faster, which isn't bad

adi10:04:32

Wondering... maybe we can have cake and eat educe it too?

(def one-to-20 (range 1 21))

(defn shuffled-20s []
  (mapcat identity (repeatedly #(shuffle one-to-20))))

(defn educe-rand-20s [n coll]
  (eduction (take n) coll))

user=> (educe-rand-20s 20 (shuffled-20s))
(11 17 1 15 13 6 16 18 20 10 4 3 2 5 19 8 14 12 7 9)

user=> (educe-rand-20s 20 (shuffled-20s)) 
(1 4 11 16 9 14 12 13 18 20 19 6 8 17 10 7 3 2 5 15)