我想知道这是否是循环收集的正确方法:
(def citrus-list ["lemon" "orange" "grapefruit"])
(defn display-citrus [citruses]
(loop [[citrus & citruses] citruses]
(println citrus)
(if citrus (recur citruses))
))
(display-citrus citrus-list)
我有三个问题:
谢谢, R上。
答案 0 :(得分:2)
首先,您的实施是错误的。如果您的列表包含nil
:
user> (display-citrus [nil "asd" "fgh"])
;;=> nil
nil
如果列表为空,则打印不需要的nil:
user> (display-citrus [])
;;=> nil
nil
你可以这样修理:
(defn display-citrus [citruses]
(when (seq citruses)
(loop [[citrus & citruses] citruses]
(println citrus)
(if (seq citruses) (recur citruses)))))
1)完全没问题:对于非空集合,函数内的最后一个调用是println
,返回nil
,而对于空集合,你不会调用任何东西,这意味着{将返回{1}}(clojure函数始终返回值)。为了避免在你的情况下为零,你应该显式返回一些值(例如这样):
nil
2)有些关于destructuring的文章可以帮助你
3)是的,有一些方法可以做到这一点。最简单的是:
(defn display-citrus [citruses]
(when (seq citruses)
(loop [[citrus & citruses] citruses]
(println citrus)
(if (seq citruses) (recur citruses))))
citruses)
user> (display-citrus citrus-list)
;;=> lemon
;;=> orange
;;=> grapefruit
["lemon" "orange" "grapefruit"]
答案 1 :(得分:2)
回答上一个问题,你应该避免在Clojure中使用loop
。这种形式适用于真正了解自己所做工作的有经验的用户。在您的情况下,您可以使用更加用户友好的表单doseq
。例如:
(doseq [item collection]
(println item))
您也可以使用map
,但请记住,它会返回一个新的列表(如果您的情况为nil
s),这有时是不可取的。比如说,您只对打印感兴趣,但不对结果感兴趣。
此外,map
是懒惰的,在使用doall
打印或评估之前,我们不会对其进行评估。
答案 2 :(得分:1)
出于大多数目的,您可以使用map
,for
或loop
。
=> (map count citrus-list)
(5 6 10)
=> (for [c citrus-list] (count c))
(5 6 10)
=> (loop [[c & citrus] citrus-list
counts []]
(if-not c counts
(recur citrus (conj counts (count c)))))
[5 6 10]
我倾向于尽可能多地使用map
。语法更简洁,它清楚地将控制流(顺序循环)与转换逻辑分开(计算值)。
例如,只需将map
替换为pmap
=> (pmap count citrus-list)
[5 6 10]
在Clojure中,most operations on collection are lazy。只要您的程序不需要新值,它们就不会生效。要立即应用效果,可以将循环操作括在doall
=> (doall (map count citrus-list))
(5 6 10)
如果您不关心返回值,也可以使用doseq
。例如,您可以将doseq
与println
一起使用,因为该函数将始终返回nil
=> (doseq [c citrus-list] (println c))
lemon
orange
grapefruit