【问题标题】:Merge (group-by) huge sequences lazily in clojure在clojure中懒惰地合并(分组)巨大的序列
【发布时间】:2016-06-16 14:19:32
【问题描述】:

示例:

我们有两个通过读取 csv 创建的时间序列惰性映射序列。这 两个惰性序列从不同的日子开始:


INPUT
 lazy-seq1
  ({:date "20110515" :val1 123}
   {:date "20110516" :val1 143}
   {:date "20110517" :val1 1153} ...)
 lazy-seq2
  ({:date "20110517" :val2 151}
   {:date "20110518" :val2 1330} ...)
EXPECTED OUTPUT
 lazy-seq3 
  ({:date "20110515" :vals {:val1 123}}
   {:date "20110516" :vals {:val1 143}}
   {:date "20110517" :vals {:val1 1153 :val2 151}}
   {:date "20110518" :vals {:val1 ... :val2 1330}}
  ...))

确切地说,:date 的类型不是字符串,而是 clj-time 强制的 Jodatime 并且 :date 为每个序列排序。

第一个选择是使用 group-by 函数,但我猜这不能创建惰性序列。我认为 group-by 需要热切的评估。

第二个选择是使用 partition-by 函数,但由于我缺乏闭包技巧,我无法将其应用于我的 INPUTS。

输入 seq 非常大(每个序列约 1GB),我想一次计算许多(约 100)个序列。 所以,我想要惰性求值来避免内存不足错误。

【问题讨论】:

  • 你的输入序列是按日期排序的吗?

标签: clojure merge data-conversion lazy-sequences


【解决方案1】:

如果您的项目按日期排序,您可以轻松地对它们进行延迟合并(如在合并排序算法中):

(defn merge-lazy [seq1 seq2]
  (cond (empty? seq1) seq2
        (empty? seq2) seq1
        (< (Integer/parseInt (:date (first seq1)))
           (Integer/parseInt (:date (first seq2)))) (cons (first seq1)
                                                      (lazy-seq (merge-lazy (rest seq1) seq2)))
        :else (cons (first seq2) (lazy-seq (merge-lazy seq1 (rest seq2))))))

它会产生一个按日期排序的惰性序列:

user> (def seq1
        '({:date "20110515" :val1 123}
          {:date "20110516" :val1 143}
          {:date "20110517" :val1 1153}))
#'user/seq1
user> (def seq2 '({:date "20110517" :val2 151}
                  {:date "20110518" :val2 1330}))

user> (merge-lazy seq1 seq2)
({:date "20110515", :val1 123} {:date "20110516", :val1 143} 
 {:date "20110517", :val2 151} {:date "20110517", :val1 1153} 
 {:date "20110518", :val2 1330})

然后你可以按日期对这个产生的惰性序列进行分区(这也会产生一个惰性序列):

user> (partition-by :date (merge-lazy seq1 seq2))
(({:date "20110515", :val1 123}) 
 ({:date "20110516", :val1 143}) 
 ({:date "20110517", :val2 151} {:date "20110517", :val1 1153})
 ({:date "20110518", :val2 1330}))

所以接下来你要做的就是用map处理每个组

如果你有更多的输入序列,你可以使用相同的策略,只是用变量 args 重写merge-lazy(或者只是用merge-lazy 重写reduce(reduce merge-lazy sequences) 这也会产生一个惰性序列的序列合并)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-12
    • 2012-12-29
    • 2010-12-17
    • 1970-01-01
    • 1970-01-01
    • 2019-06-20
    相关资源
    最近更新 更多