枚举Clojure中的序列?

dav*_*gan 21 enumeration clojure

在Python中我可以这样做:

animals = ['dog', 'cat', 'bird']
for i, animal in enumerate(animals):
    print i, animal
Run Code Online (Sandbox Code Playgroud)

哪个输出:

0 dog
1 cat
2 bird
Run Code Online (Sandbox Code Playgroud)

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

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

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

kot*_*rak 36

map-indexed1.2中有核心.

你的例子是:

(doseq [[i animal] (map-indexed vector ["dog" "cat" "bird"])]
  (println i animal))
Run Code Online (Sandbox Code Playgroud)


Leo*_*nel 8

快速解决方案

(let [animals ["dog", "cat", "bird"]]
  (map vector (range) animals))
Run Code Online (Sandbox Code Playgroud)

或者,如果要将其包装在函数中:

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

(doseq [[i animal] (enum ["dog", "cat", "bird"])]
  (println i animal))
Run Code Online (Sandbox Code Playgroud)

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

来吧,在你的repl中尝试一下.


ord*_*rig 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))
Run Code Online (Sandbox Code Playgroud)


Phi*_*per 5

map-indexed看起来不错,但是:doseq在其他答案中,我们真的需要所有的和解构的args吗?

(map-indexed println ["dog", "cat", "bird"])
Run Code Online (Sandbox Code Playgroud)

编辑: 正如@gits指出的那样,这在REPL中有效,但默认情况下不尊重clojure是惰性的。dorun似乎是最接近之中doseqdoalldoseq这一点。doseq,不过,似乎是这里的惯用法。

(dorun (map-indexed println ["dog", "cat", "bird"]))
Run Code Online (Sandbox Code Playgroud)

  • map-indexed返回一个懒惰序列。doseq是确保立即发生副作用的必要条件(在这种情况下,是由println进行的打印)。 (2认同)