简体   繁体   English

Clojure循环收集

[英]Clojure loop collection

I want to know if this is the right way to loop through an collection: 我想知道这是否是遍历集合的正确方法:

(def citrus-list ["lemon" "orange" "grapefruit"])

(defn display-citrus [citruses]
  (loop [[citrus & citruses] citruses]
    (println citrus)
    (if citrus (recur citruses))
    ))

(display-citrus citrus-list)

I have three questions: 我有三个问题:

  1. the final print displays nil, is it ok or how can avoid it? 最终打印显示为nil,可以吗?或者如何避免呢?
  2. I understand what & is doing in this example but I don´t see it in other cases, maybe you could provide a few examples 我了解此示例中的操作&但在其他情况下看不到它,也许您可​​以提供一些示例
  3. Any other example to get the same result? 还有其他示例可以获得相同的结果吗?

Thanks, R. 谢谢,R。

First of all your implementation is wrong. 首先,您的实现是错误的。 It would fail if your list contains nil : 如果您的列表包含nil ,它将失败:

user> (display-citrus [nil "asd" "fgh"])
;;=> nil
nil

And print unneeded nil if the list is empty: 如果列表为空,则打印不需要的nil:

user> (display-citrus [])
;;=> nil
nil

you can fix it this way: 您可以通过以下方式解决它:

(defn display-citrus [citruses]
  (when (seq citruses)
    (loop [[citrus & citruses] citruses]
      (println citrus)
      (if (seq citruses) (recur citruses)))))

1) it is totally ok: for non-empty collection the last call inside function is println , which returns nil , and for empty collection you don't call anything, meaning nil would be returned (clojure function always returns a value). 1)完全可以:对于非空集合,函数内部的最后一个调用是println ,它返回nil ;对于空集合,您什么都不叫,这意味着将返回nil (clojure函数始终返回一个值)。 To avoid nil in your case you should explicitly return some value (like this for example): 为了避免出现nil的情况,您应该显式返回一些值(例如,如下所示):

(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"]

2) some articles about destructuring should help you 2)有关解构的一些文章应该对您有帮助

3) yes, there are some ways to do this. 3)是的,有一些方法可以做到这一点。 The simplest would be: 最简单的是:

(run! println citrus-list)

Answering your last question, you should avoid using loop in Clojure. 回答最后一个问题,您应该避免在Clojure中使用loop This form is rather for experienced users that really know what they do. 这种形式是针对真正知道他们在做什么的有经验的用户的。 In your case, you may use such more user-friendly forms as doseq . 在您的情况下,您可以使用更加用户友好的形式,例如doseq For example: 例如:

(doseq [item collection]
  (println item))

You may also use map but keep in mind that it returns a new list (of nil s if your case) that not sometimes desirable. 您也可以使用map但是请记住,它会返回有时不希望使用的新列表(如果您的情况为nil )。 Say, you are interested only in printing but not in the result. 说,您只对打印感兴趣,而对结果不感兴趣。

In addition, map is lazy and won't be evaluated until it has been printed or evaluated with doall . 此外, map是惰性的,只有在使用doall进行打印或评估后才能对其进行评估。

For most purpose, you can use either map , for or loop . 在大多数情况下,您可以使用mapforloop

=> (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]

I tend to use map as much of possible. 我倾向于尽可能地使用map The syntax is more concise, and it clearly separates the control flow (sequential loop) from the transformation logic (count the values). 语法更加简洁,并且清楚地将控制流(顺序循环)与转换逻辑(计数值)分开。

For instance, you can run the same operation (count) in parallel by simply replacing map by pmap 例如,您可以通过简单地将map替换为pmap来并行运行相同的操作(计数)

=> (pmap count citrus-list)
[5 6 10]

In Clojure, most operations on collection are lazy . 在Clojure中, 大多数关于collection的操作都是lazy They will not take effect as long as your program doesn't need the new values. 只要您的程序不需要新值,它们就不会生效。 To apply the effect immediately, you can enclose your loop operation inside doall 要立即应用效果,可以将循环操作包含在doall

=> (doall (map count citrus-list))
(5 6 10)

You can also use doseq if you don't care about return values. 如果您不关心返回值,也可以使用doseq For instance, you can use doseq with println since the function will always return nil 例如,由于该函数将始终返回nil ,因此可以将doseqprintln配合使用

=> (doseq [c citrus-list] (println c))
lemon
orange
grapefruit

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM