开发者

Enumerate over a sequence in Clojure?

In Python I can do this:

animals = ['dog', 'cat', 'bird']
for i, animal in enumerate(animals):
    print i, animal

Which outputs:

0 dog
开发者_如何学JAVA1 cat
2 bird

How would I accomplish the same thing in Clojure? I considered using a list comprehension like this:

(println
  (let [animals ["dog" "cat" "bird"]]
    (for [i (range (count animals))
          animal animals]
      (format "%d %d\n" i animal))))

But this prints out every combination of number and animal. I'm guessing there is a simple and elegant way to do this but I'm not seeing it.


There is map-indexed in core as of 1.2.

Your example would be:

(doseq [[i animal] (map-indexed vector ["dog" "cat" "bird"])]
  (println i animal))


Quick solution:

(let [animals ["dog", "cat", "bird"]]
  (map vector (range) animals))

Or, if you want to wrap it in a function:

(defn enum [s]
  (map vector (range) s))

(doseq [[i animal] (enum ["dog", "cat", "bird"])]
  (println i animal))

What happens here is the function vector is applied to each element in both sequences, and the result is collected in a lazy collection.

Go ahead, try it in your repl.


Use indexed from clojure.contrib.seq:

Usage: (indexed s) Returns a lazy sequence of [index, item] pairs, where items come from 's' and indexes count up from zero.

(indexed '(a b c d)) => ([0 a] [1 b] [2 c] [3 d]

For your example this is

(require 'clojure.contrib.seq)
(doseq [[i animal] (clojure.contrib.seq/indexed ["dog", "cat", "bird"])]
  (println i animal))


map-indexed looks right but: Do we really need all of the doseq and deconstructing args stuff in the other answers?

(map-indexed println ["dog", "cat", "bird"])

EDIT: as noted by @gits this works in the REPL but doesn't respect that clojure is lazy by default. dorun seems to be the closest among doseq, doall and doseq for this. doseq, howver, seems to be the idiomatic favorite here.

(dorun (map-indexed println ["dog", "cat", "bird"]))


Yet another option is to use reduce-kv, which pairs the elements of a vector with their indexes.

Thus,

(reduce-kv #(println %2 %3) nil ["dog" "cat" "bird"])

or perhaps the slightly more explicit

(reduce-kv (fn [_ i animal] (println i animal)) nil ["dog" "cat" "bird"])

I wouldn’t pick this solution over the one with doseq here, but it is good to be aware of this specialisation for vectors in reduce-kv.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜