如何使用reduce执行地图

时间:2016-02-17 16:33:59

标签: clojure

你好,我有一个像这样的简单函数:

(def state
  (memoize
    (fn state [t]
      (if (<= t 0)
        0
        1))))

我试图调用(reduce state (range 10)),其意图是在state范围内调用函数0 1 2 3 4 5 ...,并接收回0 1 1 1 1 1 1 1 1 1

这种情况没有发生,因此我显然误解了一些事情,因为我得到了:

clojure.lang.ArityException: Wrong number of args (2) passed to: state

reduce的语法是(reduce f coll),我的理解是它就像执行(reduce + [1 2 3 4 5])一样简单。

显然,人们可以使用map轻松完成此操作。我只是认为reduce也会起作用。使用地图(map (fn [x] (state x)) (range 10))

PS。这只是一个测试用例,我真的需要memoization才能获得真实的东西。

由于

2 个答案:

答案 0 :(得分:3)

  

显然,人们可以很容易地使用地图做到这一点我只是觉得减少也会起作用。

是。任何map也可以是reduce。 (除了减少不是懒惰,而地图是)。

reduce函数的结果将是在函数N次迭代超过缩小范围后最终返回的结果。

您的函数返回0或1,因此,您的reduce最终将返回0或1。

如果要返回列表,则缩减功能需要返回列表。或者,使用除reduce之外的函数,例如map。

此外 - 所有减少函数都需要2个参数,而不是1.因此,state函数不是传递给reduce的有效函数。但是,传递给地图是一个有效的功能。

顺便提一下,你可以通过reduce来实现这一点,你不需要 map - 事实上,许多函数可以表示为reduce,包括map,过滤器等。但是,您需要更改缩小功能以使其兼容。

评论和其他答案表明你必须使用地图,但这里有一个减少:

(def state
     (memoize
       (fn state [r t]
         (if (<= t 0)
             (conj r 0)
             (conj r 1)))))

(reduce state [] (range 10))

;;-> [0 1 1 1 1 1 1 1 1 1]

如果您具有依赖于了解其他项目的特定项目的值的逻辑,那么这是一个很好的习惯用法。你在这里没有这样的逻辑,所以map是更好的选择。但从概念上讲,你可以用fold来表达函数式编程中的很多东西,这就是reduce

这是另一种方法,保留问题中的原始state函数,因此其记忆完好无损:

(def state
  (memoize
    (fn state [t]
      (if (<= t 0)
        0
        1))))

(defn r-fn [r t]
   (conj r (state t)))

(reduce r-fn [] (range 10))

;;-> [0 1 1 1 1 1 1 1 1 1]

这更简洁地写成:

(reduce #(conj %1 (state %2)) [] (range 10))

答案 1 :(得分:2)

嗯,那是因为reduce函数应该正好采用2个参数:累加器和来自coll的项目,如果在reduce调用期间没有提供累加器,则会减少bur,减少的第一步应用于前2个值来自coll:

(reduce + '(1 2 3 4))确实是(+ (+ (+ 1 2) 3) 4)

但这不是你所需要的:

user> (map state (range 10))
(0 1 1 1 1 1 1 1 1 1)

因为您不希望缩减为单个值,而是将映射每个值转换为另一个