2011-03-27 47 views
3

我想變換順序如下:在clojure中分組一個bools序列?

(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

短,「聰明」的解決辦法是:

(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的示例所示,在這種情況下我不認爲這是慣用的。)

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

它只是遍歷序列保持falses的電流矢量的軌跡,一切的大蓄電池至今。

+0

非常感謝您的回答;我非常喜歡它,它的作用就像一個魅力,但我將改變接受的答案,以另一個非常優雅的解決方案。再次感謝(和+1)。 – aeter 2011-03-27 20:59:23

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,從而否定了使用懶惰評估的優勢。

0

堆棧溢出錯誤是因爲你的重複發生在if之外。您評估如果形式副作用,然後無條件復發。 (隨意編輯格式,我不是在一個真正的鍵盤)。