【问题标题】:Clojure reducer/map not workingClojure减速器/地图不工作
【发布时间】:2026-02-07 06:40:01
【问题描述】:

我有一个算法如下-

(defn max-of
[args]
(into [] (apply map #(apply max %&) args)))

效果很好。

(max-of [[1 7] [3 5] [7 9] [2 2]]) 返回[7 9]

它基本上找到每个位置上的最大元素。 7 是最大的第一个元素是集合,9 是最大的第二个元素。但是,当尝试从core.reducers 使用reducer/map 时,我得到了

CompilerException clojure.lang.ArityException: Wrong number of args (21) passed to: reducers/map

所以这不起作用-

(defn max-of
[args]
(into [] (apply r/map #(apply max %&) args)))

为什么?

更新

我的最终代码是

(defn max-of [[tuple & tuples]]
  (into [] (r/fold (fn
            ([] tuple)
            ([t1 t2] (map max t1 t2)))
          (vec tuples))))

在上面跑一个快速的板凳给Execution time mean : 626.125215 ms

我有这个我之前写的其他算法 -

(defn max-fold
    [seq-arg]
    (loop [acc (transient []) t seq-arg]
        (if (empty? (first t))
            (rseq (persistent! acc))
            (recur (conj! acc (apply max (map peek t))) (map pop t)))))

它做同样的事情。为此,我得到了 - Execution time mean : 308.200310 ms,它比 r/fold 平行的东西快两倍。任何想法为什么?

顺便说一句,如果我从 r/fold 内容中删除 into [],那么我会得到 Execution time mean : 13.101313 ms

【问题讨论】:

  • 猜猜它会在没有into 的情况下给你这个结果,因为fold 是惰性的,所以直到第一次使用结果才会发生缩减
  • 我还认为由于并行处理基础设施开销,折叠方法要慢得多,这可能会被所提供任务的复杂性所抵消。在你的情况下,任务是微不足道的。此外,transient 方法是一个很好的优化,并且可能是最正确的。
  • 感谢您的所有见解

标签: dictionary clojure mapreduce


【解决方案1】:

r/map 采用 [f][f coll] - 所以你的 apply 方法在这里不起作用

user=> (doc r/map)
-------------------------
clojure.core.reducers/map
([f] [f coll])

对比

user=> (doc map)
-------------------------
clojure.core/map
([f] [f coll] [f c1 c2] [f c1 c2 c3] [f c1 c2 c3 & colls])

【讨论】:

  • 啊..谢谢。任何想法如何使用 r/map 来解决我的问题?我想我需要 r/reducer。
  • 为了清楚起见-您想找到具有最大int 的元组,无论第一还是第二位置?
  • 没有。我想在每个位置找到最大的元素。所以对于[[3 4] [5 2]],我会得到[5 4]。由于 3,5 是第一个元素,而 5 是较大的元素。同样,对于最后一个位置,它比较 4、2。返回 4 因为它更大
  • 看起来他需要创建一个 (apply max firsts) 和 (apply max seconds) 的元组。
  • 是的。但我需要它是动态的。我想为[[1 2 3] [3 4 2]][[1 2] [3 4]][[2] [6]] 使用相同的功能
【解决方案2】:

为什么这个问题的答案已经给出。那么让我们回答下一个问题:“你想做什么?”

根据我对您的目标的理解(通过元组中的位置找到最大元素)并可能并行执行(当您尝试使用减速器时),这就是您必须做的

(defn max-of [tuples]
  (r/fold (fn
            ([] (first tuples))
            ([t1 t2] (map max t1 t2)))
          ((rest tuples)))

user> (max-of [[1 7] [3 5] [7 9] [2 2]])
(7 9)

(max-of [[1 2 3] [3 2 1] [4 0 4]])
(4 2 4)

user> (max-of [])
nil

user> (max-of [[1 2 3]])
[1 2 3]

解构甚至更好:

(defn max-of [[tuple & tuples]]
  (r/fold (fn
            ([] tuple)
            ([t1 t2] (map max t1 t2)))
          tuples))

更新: 对于大数据,您应该对其进行优化并改用向量

(defn max-of [[tuple & tuples]]
  (r/fold (fn
            ([] tuple)
            ([t1 t2] (map max t1 t2)))
          (vec tuples)))

user> (max-of (repeat 1000000 [1 2 3 4 5 6 7 8 9 10]))
(1 2 3 4 5 6 7 8 9 10)

【讨论】:

  • 谢谢,这行得通。但是,当我的数据集非常大时,会出现堆栈溢出错误。它是在加载内存中的所有内容吗?
  • 它有多大?它有多少个元组?每个元组有多长?
  • 它有 420420 项。每个项目有 10 个元素。
  • 对,是我错了。 rest 返回未针对折叠优化的 seq。我会更新我的答案
  • 更新了我的答案,现在不会导致堆栈溢出