我想改变以下顺序:
(def boollist [true false false false true false true])
进入以下内容:
[[true] [false false false true] [false true]]
我的代码导致Stackoverflow:
(defn sep [boollst]
(loop [lst boollst
separated [[]]
[left right] (take 2 lst)]
(if (nil? left) separated)
(recur (next lst)
(if (false? left)
(conj (last separated) left)
(conj separated [left]))
(take 2 (next lst)))))
有没有一种优雅的方式来改变它?
答案 0 :(得分:5)
可能有一种更优雅的方式,但这就是我提出的方法:
(defn f
([xs] (f xs [] []))
([[x & xs :as all] acc a]
(if (seq all)
(if x
(recur xs [] (conj a (conj acc x)))
(recur xs (conj acc x) a))
a)))
它只是遍历序列,跟踪当前的谬误向量,以及到目前为止所有内容的大量累加器。
答案 1 :(得分:4)
一个简短的“聪明”解决方案是:
(defn sep [lst]
(let [x (partition-by identity lst)]
(filter last (map concat (cons [] x) x))))
“堆栈溢出”问题是由于Clojure关于递归的原理,如果正确接近则很容易避免。你应该总是以懒惰的方式实现这些类型的函数*:如果你找不到使用库函数解决问题的技巧,就像我上面所做的那样,你应该使用“lazy-seq”作为一般解决方案(比如pmjordan)如此解释:http://clojure.org/lazy
*占用列表并返回列表作为结果的函数。 (如果返回列表以外的其他内容,惯用解决方案是使用“recur”和累加器,如dfan的示例所示,在这种情况下我不会认为是惯用的。)
答案 2 :(得分:2)
这是一个使用延迟评估的版本,可能更具可读性:
(defn f [bools]
(when-not (empty? bools)
(let
[[l & r] bools
[lr rr] (split-with false? r)]
(lazy-seq (cons
(cons l lr)
(f rr))))))
它不返回向量,所以如果这是一个要求,你需要手动将concat和函数本身的结果传递给vec
,从而否定了使用延迟评估的优势。
答案 3 :(得分:0)
堆栈溢出错误是因为你的recur在if之外。您评估if形式的副作用,然后无条件重复。 (随意编辑格式,我不是真正的键盘)。