我试图通过尝试99个问题进入Lisps和FP。
这是问题陈述(问题15) 将列表的元素复制给定次数。我想出了……
如果你想学习惯用的Clojure,你应该尝试找到一个没有这种低水平设施的解决方案 loop 。而是试图结合更高级别的功能 take , repeat , repeatedly 。如果你喜欢冒险,你也可能会陷入懒惰。 Clojure的序列是懒惰的,即只在需要时才进行评估。
loop
take
repeat
repeatedly
我想出的一个例子是
(defn repeat-list-items [l n] (lazy-seq (when-let [s (seq l)] (concat (repeat n (first l)) (repeat-list-items (next l) n)))))
还请注意kebab-case的常见命名
这似乎做你想要的很好,并为无限输入工作(见电话 (range) 下面):
(range)
experi.core> (def l [:a :b :c]) #'experi.core/ experi.core> (repeat-list-items l 2) (:a :a :b :b :c :c) experi.core> (repeat-list-items l 0) () experi.core> (repeat-list-items l 1) (:a :b :c) experi.core> (take 10 (drop 10000 (repeat-list-items (range) 4))) (2500 2500 2500 2500 2501 2501 2501 2501 2502 2502)
复制我的评论回答:
这一行: (conj returnList head) 不修改returnlist,而只是将结果丢弃在你的情况下。您应该重新构建程序以将累积列表进一步传递到下一次迭代。但是在clojure中有更好的方法可以做到这一点。喜欢 (defn replicate-list [data times] (apply concat (repeat times data)))
(conj returnList head)
(defn replicate-list [data times] (apply concat (repeat times data)))
如果由于教育原因你仍然需要loop / recur版本,我会这样做:
(defn replicate-list [data times] (loop [[h & t :as input] data times times result []] (if-not (pos? times) result (if (empty? input) (recur data (dec times) result) (recur t times (conj result h)))))) user> (replicate-list [1 2 3] 3) ;;=> [1 2 3 1 2 3 1 2 3] user> (replicate-list [ ] 2) ;;=> [] user> (replicate-list [1 2 3] -1) ;;=> []
的 更新 强>
基于澄清的问题,最简单的方法是
(defn replicate-list [data times] (mapcat (partial repeat times) data)) user> (replicate-list [1 2 3] 3) ;;=> (1 1 1 2 2 2 3 3 3)
和loop / recur变体:
(defn replicate-list [data times] (loop [[h & t :as data] data n 0 res []] (cond (empty? data) res (>= n times) (recur t 0 res) :else (recur data (inc n) (conj res h))))) user> (replicate-list [1 2 3] 3) ;;=> [1 1 1 2 2 2 3 3 3] user> (replicate-list [1 2 3] 0) ;;=> [] user> (replicate-list [] 10) ;;=> []