【问题标题】:clojure how to execute a function on elements of two seqs concurently?clojure 如何同时对两个序列的元素执行函数?
【发布时间】:2012-02-02 23:26:50
【问题描述】:

在 Clojure 中,同时迭代两个 seq 并在两个运行元素上调用函数的最佳方法是什么? 例如:

(def a (range 3))
(def b (range 100 103))
(defn my-func [] ...) ;some custom code

代码应该执行 my-func 3 次,像这样:

(my-func 0 100)
(my-func 1 101)
(my-func 2 102)

如何在不定义任何函数或宏的情况下实现这一点?

【问题讨论】:

  • (range 100 102) 只有两个元素 - 也许你的意思是 (range 100 103)?
  • @mikera:谢谢。更新了问题

标签: clojure


【解决方案1】:

map 正是您所需要的,它接受一个函数和任意数量的 seq,并随心所欲地调用它们。

(def a (range 3))
(def b (range 100 103))
user=> a
(0 1 2)
user=> b
(100 101 102)

user=> (defn my-func [a b] (str a ":" b))
#'user/my-func

user=> (my-func 1 2)
"1:2"

user=> (map my-func a b)
("0:100" "1:101" "2:102")

因为如果你想让函数现在真正运行,map 是惰性的:

(doall (map my-func a b))

【讨论】:

  • @viebel:您是否在 REPL 上运行并使用 println?如果是这样,您的结果会令人困惑。假设你跑了(map #(println %1 ":" %2) a b),结果是REPL打印了(,然后println打印了0 : 1001 : 101,那么REPL就打印完了map的结果,也就是nil nil)
  • @Arthur Ulfeldt:我的问题的重点是寻找一种无需创建地图即可进行迭代的方法。 println 只是一个例子。我寻求的代码应该适用于任何接收 2 个参数的函数。我应该编辑问题以澄清它吗?
  • @viebel: map 做你想做的事,但println 的结果散布在 REPL 输出中。 (map f a_1 a_2 ... a_n) 调用 f,参数取自序列 a_1a_n,并以新的 seq 形式返回结果。 println 返回一个nil,所以mapping println 在集合上得到(nil nil ... nil) 作为结果。
  • 例如:(map + [1 2 3] [6 2 9] [9 2 2]) => (16 6 14)
  • @YehonathanSharvit: map 很懒(参见the page on clojure.orgsequences 也有一点),所以它在需要结果之前不会评估(这也是REPL 的原因东西穿插)。它非常方便,但在这种情况下会让你绊倒。试试(doall (map println '(1 2) '(10 20)))doall 强制评估传递给它的 seq
【解决方案2】:

你也可以试试

(doseq [[x y] (map list my-list1 my-list2)]
  (println x y))

(map list list-2 list-2) 创建一个列表,其中第一个元素是输入列表的第一个元素的列表,第二个元素是第二个元素的列表,...

然后我们遍历列表,使用 Clojure 的解构来提取原始列表的元素。

一般来说,如果你想使用你正在应用的函数的返回值,你需要map。如果你只是为了它的副作用而执行一个函数,我通常使用doseq。这种情况很复杂,因为map 并行工作,而doseq 迭代它给出的列表的Cartesian Product,所以你需要mapdoseq 来获得我们想要的行为。

【讨论】:

  • 是否有任何类似doseq 的函数可以并行迭代而不是通过笛卡尔积。如果不是,其背后的原因是什么?
  • 据我所知,没有这个功能。理想情况下,doseq/for(它们共享相同的语法)将允许类似 :and 的选项允许两个 seq 并行迭代。不幸的是,这样的选项不存在。
【解决方案3】:

(doseq ... (map 解决方案的替代方案,如果您想要成对迭代而不是笛卡尔积,您还可以将 partitioninterleave 组合起来,如下所示:

> (def a (range 0 3))
> (def b (range 100 103))
> (interleave a b)
(0 100 1 101 2 102)
> (partition 2 (interleave a b))
((0 100) (1 101) (2 102))

partition 调用提供了一个(惰性)对序列。

【讨论】:

    猜你喜欢
    • 2023-03-07
    • 1970-01-01
    • 1970-01-01
    • 2016-04-23
    • 2012-05-03
    • 1970-01-01
    • 1970-01-01
    • 2023-04-05
    • 2020-04-11
    相关资源
    最近更新 更多