Search code examples
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?
  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.


Solution

  • First of all your implementation is wrong. It would fail if your list contains nil:

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

    And print unneeded nil if the list is empty:

    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). To avoid nil in your case you should explicitly return some value (like this for example):

    (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

    3) yes, there are some ways to do this. The simplest would be:

    (run! println citrus-list)