2016-06-16 4 views
0

Пример:Merge (группы по) огромные последовательности лениво Clojure

У нас есть два временных рядов ленивых последовательностей карты, созданные чтения 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}} 
    ...)) 

Чтобы быть точным, тип: дата не строка, но Jodatime принуждены CLJ время и: дата сортируются для каждой последовательности.

Первый выбор будет использовать групповую функцию, но я думаю, что это не может создать lazy-seq. Я считаю, что группам нужна нетерпеливая оценка.

Второй вариант будет использовать функцию разбиения на разделы, но я не могу применить это к своим ВХОДАм из-за отсутствия умения закрытия.

Входной сигнал довольно большой (~ 1 ГБ на последовательность), и я хочу рассчитать много (~ 100) последовательностей сразу. Итак, мне нужна ленивая оценка, чтобы избежать ошибки Outofmemory.

+0

Ваши входные последовательности отсортированы по дате? – leetwinski

ответ

2

если ваши элементы сортируются по дате, Вы можете легко сделать ленивое слияние из них (например, в алгоритме сортировки слияния):

(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}) 

, то вы можете просто разделить это в результате ленивый SEQ по дате (который также производит ленивую следующий):

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

если у вас есть больше входных последовательностей, вы можете использовать ту же стратегию, просто переписав merge-lazy с переменной арг (или просто reduce с merge-lazy: (reduce merge-lazy sequences) это будет также производят ленивый seq последовательности слияния)