在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))))
但是这会打印出数字和动物的每一个组合。我猜有一种简单而优雅的方法可以做到这一点,但我没有看到它。
答案 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 doseq
。 doseq
,不管怎样,似乎是这里惯用的人。
(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
中向量的这种专门化。