Clojure:在字符串中查找"1"的位置,并以间隔的格式打印出来

Pau*_*uli 3 algorithm clojure

我想解决这个问题:

给定由"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)))))))
Run Code Online (Sandbox Code Playgroud)

说明:

首先,我在给定的字符串中找到"1"的位置:

(->>
    (map-indexed vector mystr)
    (filter #(= (second %) \1))
    (map (comp inc first)))
Run Code Online (Sandbox Code Playgroud)

"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 %))))
Run Code Online (Sandbox Code Playgroud)

"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在最终结果中删除s?
  2. 如何以更简洁的方式解决这个问题?

ez1*_*1sl 7

为了理解如何nil从最终结果中删除s,让我们首先了解它们是如何进入的.y在最后一个let表单中绑定到name的值实际上是所有nil值的序列.函数bar本身也会返回nil.发生这种情况是因为当条件为假并且"else"形式不存在时,print始终返回nilif返回nil.实际上,返回的序列中的每个值foo都转换为a nil.输出中的非零值是作为副作用打印的值.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"
Run Code Online (Sandbox Code Playgroud)