【问题标题】:How can I iterate over items from two different lists in Clojure in lockstep?如何以同步的方式迭代 Clojure 中两个不同列表中的项目?
【发布时间】:2019-07-09 11:13:45
【问题描述】:

我在 clojure a 和 b 中有两个长度相同的列表。我想做以下事情


for i in range(len(a)):
    if a[i] == b[i]:
        do_something(a[i], b[i])

我尝试过但没有奏效。 for 不会遍历对应的元素,而是遍历所有可能的组合:


(for [i a j b] (do-something i j))

【问题讨论】:

  • ...也就是说,Clojure 的 for 也不等同于 Python 的 for (它很懒,并且不强制评估);我想知道你是否想要doseq
  • 也就是说——你的 Clojure 参数是什么类型的?如果它们是向量,则可以直接翻译 Python 代码(对于常规的 seqs,预先获取长度可能是一项昂贵的操作)。
  • 嗯。真的,您可以只使用 (doall (map do-something a b)) 而根本不需要循环。
  • doall 被证明效率更高。
  • 嗯。它会更高效一点,因为它不会创建只是收集垃圾的瞬态向量,但如果它更有效更有效,我很好奇我们是否还有其他事情要做。

标签: clojure


【解决方案1】:

一个惯用的等价物可能是:

(doall (map do-something a b))

...或者,作为它的扩展版本,您仍然需要编写自己的循环:

(doseq [[i j] (map vector a b)]
  (do-something i j))
  • 因为for 是惰性的,它可能不会真正评估您的整个序列,除非有什么东西正在消耗它的结果; doseq 总是在所有事情上调用 do-something
  • map somefunc arg1 arg2 使用 arg1arg2 中的每组值调用 somefunc,这正是您在此处查找的内容。

更直接的翻译可能如下所示:

(doseq [i (range (count a))]
  (do-something (nth a i) (nth b i)))

...但不要使用它; countnth 都可能很慢或不可用,具体取决于使用的特定集合类型。

【讨论】:

    【解决方案2】:

    在循环中添加“if”条件:

    (doseq [[x y] (map vector a b)
            :when (= x y)]
     (do_something x y))
    

    【讨论】:

    • 嘿——我完全错过了问题的那一部分。也就是说,如果值相等,为什么要传递两个不同的参数呢?这闻起来像是在假设可变值编写逻辑的地方。
    【解决方案3】:

    如果您想使用方便的功能,I already have one 这样做:

    (ns tst.demo.core
      (:use tupelo.test)
      (:require [tupelo.core :as t]))
    
      (let [xs [ 1  2  3]
            ys [10 20 30]]
        (is= [11 22 33]
          (t/map-let [x xs
                      y ys]
            (+ x y))))
    

    因此,您将绑定写入xy,就像let 表单一样,但随后它对本地“变量”进行操作,就像在mapv 中一样。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-08-03
      • 1970-01-01
      • 2016-08-28
      • 1970-01-01
      • 2017-10-15
      • 1970-01-01
      • 1970-01-01
      • 2012-07-06
      相关资源
      最近更新 更多