首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Clojure: reduce、reduce和无限列表

Clojure: reduce、reduce和无限列表
EN

Stack Overflow用户
提问于 2011-03-08 10:00:55
回答 3查看 4.9K关注 0票数 13

Reduce和Reduce允许您在序列中累积状态。序列中的每个元素将修改累积状态,直到到达序列的末尾。

在无限列表上调用reduce或reduce意味着什么?

代码语言:javascript
复制
(def c (cycle [0]))
(reduce + c)

这将很快抛出一个OutOfMemoryError。顺便说一句,(reduce + (cycle [0]))不会抛出OutOfMemoryError (至少在我等待的时候不会抛出)。它再也不会回来了。不知道为什么。

有没有办法以一种有意义的方式调用无限列表上的reduce或reduce?我在上面的例子中看到的问题是,列表的评估部分最终变得足够大,从而使堆溢出。也许无限列表不是正确的范例。减少生成器、IO流或事件流会更有意义。该值在求值并用于修改状态后不应保留。

EN

回答 3

Stack Overflow用户

发布于 2011-03-08 10:52:43

就目前而言,亚瑟的回答是好的,但他似乎没有回答你关于reductions的第二个问题。如果给定一个只有N个元素的列表,reductions将返回reduce返回的中间阶段的延迟序列。因此,在无限列表上调用reductions是非常明智的:

代码语言:javascript
复制
user=> (take 10 (reductions + (range)))
(0 1 3 6 10 15 21 28 36 45)
票数 12
EN

Stack Overflow用户

发布于 2011-03-08 15:51:19

如果你想继续从一个列表中获取项目,比如IO流,并在运行之间保持状态,你不能使用(不使用def),相反,一个好的方法是使用循环/递归,这将允许你避免消耗太多的堆栈空间,并让你保持状态,在你的例子中:

代码语言:javascript
复制
 (loop [c (cycle [0])]
   (if (evaluate-some-condition (first c))
     (do-something-with (first c) (recur (rest c)))
     nil))

当然,与您的情况相比,这里有一个条件检查,以确保我们不会无限循环。

票数 2
EN

Stack Overflow用户

发布于 2011-03-09 03:12:37

正如其他人所指出的,直接在无限序列上运行reduce是没有意义的,因为reduce是非惰性的,需要消耗完整的序列。

作为这种情况的替代方案,这里有一个有用的函数,它只减少序列中的前n项,使用recur实现,以获得合理的效率:

代码语言:javascript
复制
 (defn counted-reduce 
  ([n f s] 
    (counted-reduce (dec n) f (first s) (rest s) ))
  ([n f initial s]
    (if (<= n 0)
      initial
      (recur (dec n) f (f initial (first s)) (rest s)))))

(counted-reduce 10000000 + (range))
=> 49999995000000
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/5227503

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档