【问题标题】:Enumerate over a sequence in Clojure?在 Clojure 中枚举一个序列?
【发布时间】:2010-11-16 15:49:35
【问题描述】:

在 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))))

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

【问题讨论】:

    标签: clojure enumeration


    【解决方案1】:

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

    你的例子是:

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

    【讨论】:

      【解决方案2】:

      快速解决方案:

      (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))
      

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

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

      【讨论】:

        【解决方案3】:

        使用索引自clojure.contrib.seq:

        用法:(indexed s) 返回 [index, item] 对的惰性序列,其中项目来自 from '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))
        

        【讨论】:

        【解决方案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"]))
        

        【讨论】:

        • map-indexed 返回一个惰性序列。 doseq 是确保副作用现在而不是以后发生所必需的(在这种情况下,打印由 println 影响)。
        • @git 对,谢谢,我注意到了,但没有更新,因为我还在学习,不知道doseq 是否是这里真正最喜欢的成语。
        【解决方案5】:

        另一种选择是使用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 中的向量的这种专门化。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2010-09-11
          • 2012-02-06
          • 1970-01-01
          • 2023-04-11
          • 2010-12-22
          • 2022-11-14
          相关资源
          最近更新 更多