枚举Clojure中的序列?

时间:2010-11-16 15:49:36

标签: clojure enumeration

在Python中,我可以这样做:

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

哪个输出:

0 dog
1 cat
2 bird

我如何在Clojure中完成同样的事情?我考虑使用这样的列表理解:

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

但是这会打印出数字和动物的每一个组合。我猜有一种简单而优雅的方法可以做到这一点,但我没有看到它。

5 个答案:

答案 0 :(得分:34)

从1.2开始,核心中有map-indexed

你的例子是:

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

答案 1 :(得分:8)

快速解决方案:

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

或者,如果你想把它包装在一个函数中:

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

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

这里发生的是函数向量应用于两个序列中的每个元素,结果收集在一个惰性集合中。

继续,在您的副本中尝试。

答案 2 :(得分:8)

使用从clojure.contrib.seq索引:

用法:(indexed s) 返回项目到来的[index,item]对的延迟序列 从's'和索引从零开始计算。

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

对于你的例子,这是

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

答案 3 :(得分:4)

map-indexed看起来正确,但是:我们真的需要所有doseq并解构其他答案中的args内容吗?

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

修改 正如@gits所述,这在REPL中起作用,但不尊重clojure默认是懒惰的。 dorun似乎是最接近的among doseq, doall and doseqdoseq,不管怎样,似乎是这里惯用的人。

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

答案 4 :(得分:1)

另一种选择是使用reduce-kv,它将向量的元素与其索引配对。

因此,

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

或者稍微更明确的

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

我不会在这里使用doseq选择此解决方案,但最好注意reduce-kv中向量的这种专门化。