以下是一些值。每个都是一系列升序(或其他分组)的值。
(def input-vals [[[1 :a] [1 :b] [2 :c] [3 :d] [3 :e]]
[[1 :f] [2 :g] [2 :h] [2 :i] [3 :j] [3 :k]]
[[1 :l] [3 :m]]])
我可以按值对它们进行分区。
=> (map (partial partition-by first) input-vals)
((([1 :a] [1 :b]) ([2 :c]) ([3 :d] [3 :e])) (([1 :f]) ([2 :g] [2 :h] [2 :i]) ([3 :j] [3 :k])) (([1 :l]) ([3 :m])))
但这让我获得了3个分区序列。我想要一个分区组序列。
我想要做的是返回一个(潜在的)延迟序列的懒惰序列,这些序列是连接的相应分区。例如我想要产生这个:
((([1 :a] [1 :b] [1 :f] [1 :l]) ([2 :c] [2 :g] [2 :h] [2 :i]) ([3 :d] [3 :e] [3 :j] [3 :k] [3 :m])))
请注意,并非所有值都出现在所有序列中(第三个向量中没有2
)。
这当然是我问题的简化。真实数据是来自非常大的文件的一组延迟流,因此无法实现任何内容。但我认为上述问题的解决方案是我的问题的解决方案。
随意编辑标题,我不太清楚如何表达它。
答案 0 :(得分:2)
试试这个恐怖:
(defn partition-many-by [f comp-f s]
(let [sorted-s (sort-by first comp-f s)
first-list (first (drop-while (complement seq) sorted-s))
match-val (f (first first-list))
remains (filter #(not (empty? %))
(map #(drop-while (fn [ss] (= match-val (f ss))) %)
sorted-s))]
(when match-val
(cons
(apply concat
(map #(take-while (fn [ss] (= match-val (f ss))) %)
sorted-s))
(lazy-seq (partition-many-by f comp-f remains))))))
可以改进删除双值检查(take-while和drop-while)。
使用示例:
(partition-many-by identity [[1 1 1 1 2 2 3 3 3 3] [1 1 2 2 2 2 3] [3]])
=> ((1 1 1 1 1 1) (2 2 2 2 2 2) (3 3 3 3 3 3))
答案 1 :(得分:2)
让我们感兴趣并使用无限长度的序列作为我们的输入
(def twos (iterate #(+ 2 %) 0))
(def threes (iterate #(+ 3 %) 0))
(def fives (iterate #(+ 5 %) 0))
我们需要懒洋洋地合并它们。我们要求比较器,以便我们也可以应用于其他数据类型。
(defn lazy-merge-by
([compfn xs ys]
(lazy-seq
(cond
(empty? xs) ys
(empty? ys) xs
:else (if (compfn (first xs) (first ys))
(cons (first xs) (lazy-merge-by compfn (rest xs) ys))
(cons (first ys) (lazy-merge-by compfn xs (rest ys)))))))
([compfn xs ys & more]
(apply lazy-merge-by compfn (lazy-merge-by compfn xs ys) more)))
测试
(take 15 (lazy-merge-by < twos threes fives))
;=> (0 0 0 2 3 4 5 6 6 8 9 10 10 12 12)
如果需要,我们可以(懒惰地)按值分区
(take 10 (partition-by identity (lazy-merge-by < twos threes fives)))
;=> ((0 0 0) (2) (3) (4) (5) (6 6) (8) (9) (10 10) (12 12))
现在,回到示例输入
(partition-by first (apply lazy-merge-by #(<= (first %) (first %2)) input-vals))
;=> (([1 :a] [1 :b] [1 :f] [1 :l]) ([2 :c] [2 :g] [2 :h] [2 :i]) ([3 :d] [3 :e] [3 :j] [3 :k] [3 :m]))
根据需要减去一组无关的外括号。
答案 2 :(得分:1)
我不确定我是否关注,但你可以对结果序列进行评估,例如:
(flatten (partition-by identity (first input-vals)))
clojure.core /平铺
([X])
采用顺序事物的任何嵌套组合(列表,向量,
等)并将其内容作为单个平面序列返回 (flatten nil)返回一个空序列。
你可以用实现吗?用于测试序列是否是惰性的函数。
答案 3 :(得分:1)
user> (def desired-result '((([1 :a] [1 :b] [1 :f] [1 :l])
([2 :c] [2 :g] [2 :h] [2 :i])
([3 :d] [3 :e] [3 :j] [3 :k] [3 :m]))))
#'user/desired-result
user> (def input-vals [[[1 :a] [1 :b] [2 :c] [3 :d] [3 :e]]
[[1 :f] [2 :g] [2 :h] [2 :i] [3 :j] [3 :k]]
[[1 :l] [3 :m]]])
#'user/input-vals
user> (= desired-result (vector (vals (group-by first (apply concat input-vals)))))
true
我稍微更改了输入值以纠正我认为是打字错误,如果不是错误我可以更新我的代码以适应不太规则的结构。
使用->>
(thread last)宏,我们可以以更易读的形式获得等效代码:
user> (= desired-result
(->> input-vals
(apply concat)
(group-by first)
vals
vector))
true
答案 4 :(得分:0)
(partition-by first (sort-by first (mapcat identity input-vals)))