这里有三个版本:一个简单的、严格的;一个基于clojure.core
组合器的懒惰的;和一个基于相同组合器的惰性组合器,它接受任意数量的输入。
一个简单的严格方法
对惰性方法的健全性检查。
(defn interleave-longer-strict [xs ys]
(take (* 2 (max (count xs) (count ys)))
(interleave (cycle xs) (cycle ys))))
基于组合器的惰性方法
这是一个基于map
, mapcat
, take-while
, iterate
,interleave
和的懒惰版本cycle
:
(defn interleave-longer
"Lazy version of
(take (* 2 (max (count xs) (count ys)))
(interleave (cycle xs) (cycle ys)))"
[xs ys]
(map (fn [_ e] e)
(mapcat (fn [[xs ys]] [[xs ys] [xs ys]])
(take-while (fn [[xs ys]] (or xs ys))
(iterate (fn [[xs ys]] [(next xs) (next ys)])
[xs ys])))
(interleave (cycle xs) (cycle ys))))
为了证明它确实是惰性的(注意,(range)
永远不会返回——如果你真的通过 消耗它Long/MAX_VALUE
,它只会开始返回clojure.lang.BigInt
s):
(take 30 (interleave-longer (range) (range 11)))
;= (0 0 1 1 2 2 3 3 4 4 5 5 6 6 7 7 8 8 9 9 10 10 11 0 12 1 13 2 14 3)
(take 30 (interleave-longer (range 11) (range)))
;= (0 0 1 1 2 2 3 3 4 4 5 5 6 6 7 7 8 8 9 9 10 10 0 11 1 12 2 13 3 14)
使用可变参数的基于组合器的惰性方法
最后,一个基于相同原语的惰性版本 plus apply
, repeat
and count
(应用于 varargs seq 以确定有多少输入)接受任意数量的输入:
(defn interleave-longest [& xss]
(map (fn [e & _] e)
(apply interleave (map cycle xss))
(mapcat (fn [xss] (repeat (count xss) xss))
(take-while (fn [xss] (some some? xss))
(iterate (fn [xss] (mapv next xss))
xss)))))
在 REPL:
(interleave-longest [:a :b :c :d] (range 11) '[x y z])
;= (:a 0 x :b 1 y :c 2 z :d 3 x :a 4 y :b 5 z :c 6 x :d 7 y :a 8 z :b 9 x :c 10 y)
(take 30 (interleave-longest [:a :b :c :d] (range) '[x y z]))
;= (:a 0 x :b 1 y :c 2 z :d 3 x :a 4 y :b 5 z :c 6 x :d 7 y :a 8 z :b 9 x)