;; create lazy infinite seq of random ints
(def infi-seq (repeatedly #(rand-int 11)))
(take 5 infi-seq) ; => (8 2 9 9 5)
How can I get all values realized (8 2 9 9 2)
without knowing that the first five values have been realized?
;; create lazy infinite seq of random ints
(def infi-seq (repeatedly #(rand-int 11)))
(take 5 infi-seq) ; => (8 2 9 9 5)
How can I get all values realized (8 2 9 9 2)
without knowing that the first five values have been realized?
This should do the trick:
(defn take-realized
[coll]
(if-not (instance? clojure.lang.IPending coll)
(cons (first coll) (take-realized (rest coll)))
(when (realized? coll)
(cons (first coll) (take-realized (rest coll))))))
You can modify or use count-realized
(defn count-realized [s]
(loop [s s, n 0]
(if (instance? clojure.lang.IPending s)
(if (and (realized? s) (seq s))
(recur (rest s) (inc n))
n)
(if (seq s)
(recur (rest s) (inc n))
n))))
Note the check for IPending is necessary for cases where non-lazy elements prepend the sequence, as in iterate.
(def foo (iterate inc 1))
(take (count-realized foo) foo)
;=> (1)
(dorun (take 5 foo))
;=> nil
(take (count-realized foo) foo)
;=> (1 2 3 4 5)
Perhaps this:
(defn take-realized [coll]
(map first (take-while realized? (iterate rest coll))))
Neat but meretricious. It can be fixed to some extent:
(defn take-realized [coll]
(->> coll
(iterate next)
(take-while #(and % (or (not (instance? clojure.lang.IPending %)) (realized? %))))
(map first)))
But this still produces an infinite lazy sequence with iterate
:
(take 5 (take-realized (iterate inc 0)))
;(0 1 2 3 4)
The other answers are superior.