3

我想根据值的序列对序列进行分区

(partition-by-seq [3 5] [1 2 3 4 5 6]) 
((1 2 3)(4 5)(6))

第一个输入是一个分割点序列。第二个输入是我想要分区的序列。因此,第一个列表将以值 3 (1 2 3) 进行分区,第二个分区将是 (4 5),其中 5 是下一个分割点。

另一个例子:

(partition-by-seq [3] [2 3 4 5])
result: ((2 3)(4 5))

(partition-by-seq [2 5] [2 3 5 6])
result: ((2)(3 5)(6))

给定:第一个 seq(分割点)始终是第二个输入 seq 的子集。

4

3 回答 3

1

要分割的序列是 a splittee,分割点(aka. splitter)的元素标记了分割的最后一个元素。

从你的例子:

分裂者:[1 2 3 4 5 6]

分离器:[3 5]

结果:((1 2 3)(4 5)(6))

因为得到的分区总是一个递增的整数序列,并且递增的整数序列x可以定义为start <= x < end,所以拆分器元素可以end根据定义转换为一个序列。

所以,从[3 5],我们想找到以4和结尾的子序列6

然后通过添加startsplitter可以转换为 的序列[start end]startend使用了分流器的 and 。

所以,分离器[3 5]就变成了:

[[1 4] [4 6] [6 7]]

拆分器转换可以这样完成

(->> (concat [(first splittee)] 
              (mapcat (juxt inc inc) splitter) 
              [(inc (last splittee))])
     (partition 2)

splitter转换后的结果和期望的结果之间有很好的对称性。

[[1 4] [4 6] [6 7]]

((1 2 3) (4 5) (6))

那么问题就变成了如何提取splittee[start end]内部转换拆分器划分的子序列

clojure 具有subseq可用于在有序序列按startend标准中查找子序列的功能。我可以为transformed-splitter的每个元素映射splittee的子序列

(map (fn [[x y]]
       (subseq (apply sorted-set splittee) <= x < y))
     transformed-splitter)

通过结合上述步骤,我的答案是:

(defn partition-by-seq 
  [splitter splittee]
  (->> (concat [(first splittee)]
                (mapcat (juxt inc inc) splitter)
                [(inc (last splittee))])
       (partition 2)
       (map (fn [[x y]]
              (subseq (apply sorted-set splittee) <= x < y)))))
于 2015-03-17T17:17:36.380 回答
1

我想出了这个懒惰且非常(IMO)直截了当的解决方案。

(defn part-seq [splitters coll]
  (lazy-seq
   (when-let [s (seq coll)]
     (if-let [split-point (first splitters)]
       ; build seq until first splitter
       (let [run (cons (first s) (take-while #(<= % split-point) (next s)))]
         ; build the lazy seq of partitions recursively
         (cons run
               (part-seq (rest splitters) (drop (count run) s))))
       ; just return one partition if there is no splitter 
       (list coll)))))

如果分割点都在序列中:

(part-seq [3 5 8] [0 1 2 3 4 5 6 7 8 9])
;;=> ((0 1 2 3) (4 5) (6 7 8) (9))

如果某些分割点不在序列中

(part-seq [3 5 8] [0 1 2 4 5 6 8 9])
;;=> ((0 1 2) (4 5) (6 8) (9))

拆分器的一些无限序列和要拆分的序列的示例。

(take 5 (part-seq (iterate (partial + 3) 5) (range)))
;;=> ((0 1 2 3 4 5) (6 7 8) (9 10 11) (12 13 14) (15 16 17))
于 2015-03-18T16:40:38.377 回答
0

这是我想出的解决方案。

(def a [1 2 3 4 5 6])
(def p [2 4 5])

(defn partition-by-seq [s input]
  (loop [i 0 
         t input
         v (transient [])]
    (if (< i (count s))
        (let [x (split-with #(<= % (nth s i)) t)]
          (recur (inc i) (first (rest x)) (conj! v (first x))))
      (do
        (conj! v t)
        (filter #(not= (count %) 0) (persistent! v))))))

(partition-by-seq p a)
于 2015-03-17T17:02:25.797 回答