在Clojure中使用累加器的映射?
我想按顺序映射一个序列,但想向前携带一个累加器值,就像在reduce中一样 示例用例:获取一个向量并返回一个运行总数,每个值乘以2在Clojure中使用累加器的映射?,clojure,Clojure,我想按顺序映射一个序列,但想向前携带一个累加器值,就像在reduce中一样 示例用例:获取一个向量并返回一个运行总数,每个值乘以2 (defn map-with-accumulator "Map over input but with an accumulator. func accepts [value accumulator] and returns [new-value new-accumulator]." [func accumulator collection] (if (
(defn map-with-accumulator
"Map over input but with an accumulator. func accepts [value accumulator] and returns [new-value new-accumulator]."
[func accumulator collection]
(if (empty? collection)
nil
(let [[this-value new-accumulator] (func (first collection) accumulator)]
(cons this-value (map-with-accumulator func new-accumulator (rest collection))))))
(defn double-running-sum
[value accumulator]
[(* 2 (+ value accumulator)) (+ value accumulator)])
给
(prn (pr-str (map-with-accumulator double-running-sum 0 [1 2 3 4 5])))
>>> (2 6 12 20 30)
为了说明通用性,另一个示例是将运行总和打印为星号和原始数字。一个稍微复杂的示例,但演示了我需要在map函数中保持累加器的运行:
(defn stars [n] (apply str (take n (repeat \*))))
(defn stars-sum [value accumulator]
[[(stars (+ value accumulator)) value] (+ value accumulator)])
(prn (pr-str (map-with-accumulator stars-sum 0 [1 2 3 4 5])))
>>> (["*" 1] ["***" 2] ["******" 3] ["**********" 4] ["***************" 5])
这很好,但我希望这是一种常见的模式,并且在
core
中存在某种带有累加器的映射。是吗?你应该研究一下减少量。对于这一具体情况:
(reductions #(+ % (* 2 %2)) 2 (range 2 6))
产生
(2 6 12 20 30)正如迭戈所提到的那样,减排是一条路,但是对于您的具体问题,以下方法可行
(map #(* % (inc %)) [1 2 3 4 5])
一般解决方案
映射的公共模式可以同时依赖于项和序列的累积和,由函数捕获
(defn map-sigma [f s] (map f s (sigma s)))
在哪里
(def sigma (partial reductions +))
。。。返回序列的累加和的序列:
(sigma (repeat 12 1))
; (1 2 3 4 5 6 7 8 9 10 11 12)
(sigma [1 2 3 4 5])
; (1 3 6 10 15)
在map sigma
的定义中,f
是两个参数的函数,该项后跟累加器
示例
在这些术语中,可以表示第一个示例
(map-sigma (fn [_ x] (* 2 x)) [1 2 3 4 5])
; (2 6 12 20 30)
(map-sigma #(vector (stars %2) %1) [1 2 3 4 5])
; (["*" 1] ["***" 2] ["******" 3] ["**********" 4] ["***************" 5])
在这种情况下,映射函数忽略该项,并且仅依赖于累加器
第二个可以表达
(map-sigma (fn [_ x] (* 2 x)) [1 2 3 4 5])
; (2 6 12 20 30)
(map-sigma #(vector (stars %2) %1) [1 2 3 4 5])
; (["*" 1] ["***" 2] ["******" 3] ["**********" 4] ["***************" 5])
。。。其中,映射函数取决于项和累加器
没有像map sigma
这样的标准函数
一般结论
- 仅仅因为计算模式很常见并不意味着
它值得或需要自己的标准功能
- 惰性序列和序列库功能强大,足以挑逗
将许多问题分解成清晰的函数组合李>
重写为特定于提出的问题
编辑以适应已更改的第二个示例 如前所述,您可以使用缩减
:
这只是在你想保持原有要求的情况下。否则,我宁愿将f
分解为两个独立的函数,并使用缩略图的方法。谢谢。不过,我不确定这是否抓住了我问题的一般性(我必须对其进行说明,但说明可能没有充分展示一般性)。我添加了另一个例子。很抱歉延迟接受,我想确保这涵盖了我的用例。是的,谢谢,谢谢。这解决了“我如何计算这个数字序列”而不是“这个高阶函数存在吗?”。我想这是我举个例子的错。无论如何,我已经添加了另一个来说明。谢谢你的回答,但我认为这回答了示例,而不是实际问题(运行累加器可用的地图)。我已经编辑了星星来演示这一点(注意,我没有更改我要问的问题或函数!)。@Joe-改编为使运行的累加器可用于任何映射。非常感谢您的回答和努力。我接受了另一个,因为他是第一个,对不起。如果可以,我会加倍投票@乔:没问题。我必须自己把它做好。洞察是参数化:一旦看到就显而易见,但更难捕捉。关于函数式编程,问题的完美表达就是答案。