Clojure操纵字符串序列

时间:2013-08-20 12:48:50

标签: vector clojure reduce

我有一个["a" "b" " c" "d" " e" " f" "g"]

形式的数据结构

我想将其减少到["a" "b c" "d e f" "g"],也就是说,以空格开头的字符串会加到前面的字符串中。

我已经苦苦挣扎了几个小时,我正在寻找一些灵感!

4 个答案:

答案 0 :(得分:2)

这会将字符串序列拆分成块,然后连接所有字符串组,每个字符串应该加入一个string/join调用,这样就可以避免解决方案将字符串串联起来的二次行为:

(def xs ["a" "b" " c" "d" " e" " f" "g"])

(require '[clojure.string :as string])

(->> xs
     (partition-by #(.startsWith ^String % " "))
     (map vec)
     (partition-all 2)
     (reduce (fn [acc [ps ss]]
               (-> acc
                   (into (pop ps))
                   (conj (string/join "" (cons (peek ps) ss)))))
             []))
;= ["a" "b c" "d e f" "g"]

请注意,这假定第一个字符串不以空格开头。为了废除这个假设,您可以在上面添加一个空字符串((cons "" xs)而不是xs,或者(cons "")作为第一个->>步骤)以“捕获”他们。在这种情况下,结果将以一个字符串开头,这个字符串是将序列初始字符串以空格开头,或者如果序列不以这样的字符串开头,则将空格连接起来,这样就可以检查是否存在""在结果的第一个位置,可能会过滤掉它。

答案 1 :(得分:1)

以下是使用reduce进行此操作的一种方法,尽管可能有一种更优雅的方式来做同样的事情 - 通常在Clojure中:)

(defn join-when-space [v]
   (->> (reduce (fn [acc next-value]
                   (if (re-matches #"^ .*" next-value)
                     (concat (butlast acc) [(str (last acc) next-value)])
                     (concat acc [next-value]))) 
                [[] (first v)] (rest v))
         rest
         (into [])))

答案 2 :(得分:1)

混合方法,其中过滤器和初始累加器处理第一个以空格大小写开始。

(defn join-when-space [vs]
  (mapv (partial apply str) 
    (filter not-empty 
      (reduce (fn [a s] (if (re-find #"^\s" s) 
                          (conj (pop a) (conj (peek a) s)) 
                          (conj a [s]))) 
         [[]] vs))))

答案 3 :(得分:0)

此函数生成一个在初始空格上拼接的序列 strings 的延迟序列:

(defn spliced-seq [strings]
  (let [[x & xs] strings]
   (if (empty? xs)
    [x]
    (let [[ys & ns] (split-with #(.startsWith % " ") xs)]
      (cons (apply str x ys) (lazy-seq (f ns)))))))

然后(vec (spliced-seq) ["a" " b" " c" "d" "e"]))生成["a b c" "d e"]