我有一个包含数字的向量。 矢量的结构如下:
我想写一个函数split
来检索项目列表(没有分隔符):它类似于string/split。
例如:
(split [123 0 1 0 0 0 0 0 1 1 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0 1 199])
; => [[123 0 1] [1 1] [1 0 1] [0 0 1 199]]
备注:代码必须有效,因为向量的长度约为100万。
感谢您的帮助。
答案 0 :(得分:4)
下面:
(defn the-split [coll]
(let [part (partition-by identity coll)
ppart (partition-by #(= [0 0 0 0 0] %) part)
almost (map #(apply concat %) ppart)]
(filter (partial not= [0 0 0 0 0]) almost)))
(the-split [123 0 1 0 0 0 0 0 1 1 0 0 0 0 0 1 0 1 0 0 0 0 0 1 199])
=> ((123 0 1) (1 1) (1 0 1) (1 199))
答案 1 :(得分:2)
这是一种方法 - 将[0 0 0 0 0]
分隔符硬连线,但直截了当地概括:
(defn split5z [xs]
(let [delim [0 0 0 0 0]
step (fn step [xs seg]
(lazy-seq
(if-let [xs (seq xs)]
(let [window (take 5 xs)]
(if (= window delim)
(cons seg (step (drop 5 xs) []))
(step (rest xs) (conj seg (first xs)))))
(list seg))))]
(step xs [])))
将其应用于您的样本输入:
(split5z [123 0 1 0 0 0 0 0 1 1 0 0 0 0 0 1 0 1 0 0 0 0 0 1 199])
;= ([123 0 1] [1 1] [1 0 1] [1 199])
如果您希望输出为向量而不是seq的向量,请将vec
换行。
另一种方法 - 这次热切地使用loop
/ recur
消费输入:
(defn split5z [sep xs]
(let [scnt (count sep)]
(loop [xs (seq xs)
out []
seg []]
(if xs
(if (= (take scnt xs) sep)
(recur (nthnext xs scnt)
(conj out seg)
[])
(recur (next xs)
out
(conj seg (first xs))))
(if (seq seg)
(conj out seg)
seg)))))
在REPL:
(split5z [0 0 0 0 0]
[123 0 1 0 0 0 0 0 1 1 0 0 0 0 0 1 0 1 0 0 0 0 0 1 199])
;= [[123 0 1] [1 1] [1 0 1] [1 199]]
答案 2 :(得分:1)
懒惰的解决方案:
(defn split [v]
(let [delim (repeat 5 0)
i (->> v (partition 5 1) (take-while #(not= delim %)) count)]
(if (zero? i) [v] (lazy-seq (cons (subvec v 0 i)
(split (subvec v (+ i 5))))))))
例如
(split [123 0 1 0 0 0 0 0 1 1 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0 1 199])
; ([123 0 1] [1 1] [1 0 1] [0 0 1 199])