2014-12-23 82 views
3

我特林解決這樣的問題的格式打印出他們:的Clojure:查找字符串的「1」的位置和間隔

鑑於組成的「1」和「0」的字符串,找到「1」的所有位置,並以間隔的格式打印它們。

例如: "00101110101110" => 3, 5-7, 9, 11-13

我(醜)解決方案:

(defn bar [x] 
    (letfn [(foo [mystr] 
      (->> 
       (map-indexed vector mystr) 
       (filter #(= (second %) \1)) 
       (map (comp inc first)) 
       (partition-all 2 1) 
       (filter #(= 2 (count %)))))] 
    (let [y (map #(if (> (- (second %) (first %)) 1) (print (first %) ", " (second %) "-")) (foo x))] 
     (print (ffirst y) "-" y (last (last (foo x))))))) 

說明:

起初,我發現的 「1」 給定字符串中的位置:

(->> 
    (map-indexed vector mystr) 
    (filter #(= (second %) \1)) 
    (map (comp inc first))) 

"00101110101110" => (3 5 6 7 9 11 12 13)

然後,我將位置列表分割成2元素元組序列。如果有一個1-元件元組在該序列結束時,拖放:

(->> 
    (map-indexed vector mystr) 
    (filter #(= (second %) \1)) 
    (map (comp inc first)) 
    (partition-all 2 1) 
    (filter #(= 2 (count %)))) 

"00101110101110" => ((3 5) (5 6) (6 7) (7 9) (9 11) (11 12) (12 13))

最後,打印出在第一元組中的第一位置,而第二個在最後一個元組,同時僱用 (map #(if (> (- (second %) (first %)) 1) (print (first %) ", " (second %) "-")) (foo x))獲取中間部分。

輸入: (bar "00101110101110")

最終結果: 3 , 5 -nil - (nil nil 7 , 9 -nil 9 , 11 -nil nil nil nil) 13

我的問題:

  1. 我如何刪除nil進入決賽結果如何呢?
  2. 如何以更簡潔的方式解決此問題?

回答

7

爲了理解如何從最終結果中刪除nil,讓我們先了解它們是如何進入到最初的。在最後的let表格中綁定到名稱y的值實際上是所有nil值的序列。函數bar本身也返回nil。發生這種情況是因爲print總是返回nilif返回nil當條件爲false並且「else」形式不存在時。實際上,由foo返回的序列中的每個值都將轉換爲nil。輸出中的非零值是作爲副作用打印的值。 nil和非零值是混合的,因爲map是惰性的,僅當最後的print實現了惰性序列y時才應用映射函數。不用說,使用map作爲副作用是一個壞主意。

因此,從輸出中刪除nil s的最簡單方法是完全避免使用nil值。

(->> "00101110101110" 
    (map-indexed vector)       ;; ([0 \0] [1 \0] [2 \1]... 
    (partition-by second)      ;; (([0 \0] [1 \0]) ([2 \1]) ([3 \0]) ([4 \1] [5 \1] [6 \1]) ... 
    (filter #(= \1 (-> % first second)))   ;; (([2 \1]) ([4 \1] [5 \1] [6 \1])... 
    (map #(map (comp inc first) %))    ;; ((3) (5 6 7) (9) (11 12 13)) 
    (map #(if (next %) [(first %) (last %)] %)) ;; ((3) [5 7] (9) [11 13]) 
    (map #(clojure.string/join "-" %))   ;; ("3" "5-7" "9" "11-13") 
    (clojure.string/join ", ")) 
;; => "3, 5-7, 9, 11-13" 
0

我發現這個問題還挺有趣的,所以我試圖用這種方法from this talk進行攻擊:通過映射數據更高的並行成一個更方便的空間,然後在並行子相結合的解決方案。爲此,我專注於同時生產這些間隔。使用傳感器執行所有中間步驟,然後製作一個eductionfold。這種組織爲一些輔助功能等提供了幫助,所以在簡潔方面可能不那麼好,但希望有趣。

我經過中間表示爲嵌套載體:[accepted boundary],其中由2維矢量boundary表示的間隔增長,直到有一個不連續,在這種情況下,它被添加到accepted結束。

(defn indices "Transducer finding indices of an element occuring in a sequence" 
    [element] 
    (keep-indexed #(when (= element %2) %1))) 

(defn combine "Combine two series of intervals" 
    ([] [[] nil]) 
    ([[acc-a bnd-a] [acc-b bnd-b]] 
    (let[ [[a b] [c d]] [bnd-a (first acc-b)] ] 
    (if (<= b c (inc b)) 
     [(into acc-a (concat [[a d]] (pop acc-b))) bnd-b] 
     [(into acc-a (concat [bnd-a] acc-b)) bnd-b])))) 

(defn plus "Add an interval to the series" 
    ([] [[] nil]) 
    ([[accepted boundary] to-add] 
    (if (nil? boundary) 
    [accepted to-add] 
    (let[[[a b] [c d]] [boundary to-add]] 
     (if (<= b c (inc b)) 
     [accepted [a d]] 
     [(conj accepted boundary) to-add]))))) 

(defn printable-indices [element the-seq] 
    (let[glommed (clojure.core.reducers/fold combine plus (eduction (comp (indices \1) (map #(vector % %))) the-seq)) 
     fixed-up (conj (first glommed) (last glommed))] ;;Because the reduction is done, the last boundary is now accepted. 
    (clojure.string/join ", " (map (fn [[a b]](if (= a b) (str a) (str a \- b)))) fixed-up))) 
相關問題