在clojure中分组一系列bool?

时间:2011-03-27 19:12:42

标签: clojure

我想改变以下顺序:

(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)))))

有没有一种优雅的方式来改变它?

4 个答案:

答案 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形式的副作用,然后无条件重复。 (随意编辑格式,我不是真正的键盘)。