延迟序列min-max finder stackoverflow问题

时间:2011-04-26 18:33:32

标签: clojure lazy-evaluation

 (defn min-max-by-columns [s]
   (reduce (fn [[smallest largest] y]
            [(map min smallest y) (map max largest y)])
      [(first s) (first s)]
      s))

我试图找出一张大表的每列的最大值和最小值(固定长度序列的序列)

上面的代码适用于小型表,但对于大型表,我得到一个stackoverflow错误

clojure.core/map/fn--3594 (core.clj:2370)
clojure.lang.LazySeq.sval (LazySeq.java:42)
clojure.lang.LazySeq.seq (LazySeq.java:60)
clojure.lang.RT.seq (RT.java:447)
clojure.core/seq (core.clj:133)
clojure.core/map/fn--3594 (core.clj:2371)
clojure.lang.LazySeq.sval (LazySeq.java:42)
clojure.lang.LazySeq.seq (LazySeq.java:60)
clojure.lang.RT.seq (RT.java:447)
clojure.core/seq (core.clj:133)
clojure.core/map/fn--3594 (core.clj:2371)
clojure.lang.LazySeq.sval (LazySeq.java:42)
clojure.lang.LazySeq.seq (LazySeq.java:60)
clojure.lang.RT.seq (RT.java:447)
clojure.core/seq (core.clj:133)
clojure.core/map/fn--3594 (core.clj:2371)

...

我是否因为线[(第一个)(第一个)]而坚持到头部?我需要这些值来使算法起作用。

我该如何解决这个问题?

2 个答案:

答案 0 :(得分:3)

我似乎找到了解决方案。正如合金所解释的那样,(映射最小的x)和(映射最大的最大x)正在同时实现。然而,我试图解决与他正在解决的问题不同的问题。幸运的是,他的洞察力帮助我找到了解决方案;诀窍是围绕每个地图包裹一个doall,以便在中间步骤中实现它们,而不是在最后一次执行时。

 (defn min-max-by-columns [s]
   (reduce (fn [[smallest largest] y]
         [(doall (map min smallest y)) (doall (map max largest y))])
       [(first s) (first s)]
       s))

答案 1 :(得分:2)

(map min smallest y)没有任何意义。您没有计算新的最小数字,而是返回[(min smallest) (min y)]的惰性序列。最终,这些懒惰的地图堆积在彼此之上,你立即意识到它们。这很容易修复,因为你不想要开始映射任何东西!

我有点惊讶你说这对于小序列“有效”。我可以看到它没有炸毁堆栈(当然),但我不知道它是如何计算出正确答案的。无论如何,我的解决方案是

(defn min-max-by-columns [[x & xs]]
  (reduce (fn [[smallest largest] x]
            [(min smallest x) (max largest x)])
          [x x]
          xs))