2011-11-21 52 views
2

的一箇中等規模的名單,我需要一個非常快速和有效的方式來「轉」 Clojure中的地圖列表。Clojure的:「轉」有效映射

比方說,我有:

(def monthly-sales [{:month 1 :pc "A" :sales 100} 
{:month 2 :pc "B" :sales 200} ... {:month 12 :pc "Z" :sales 100}]) 

我需要這樣的:

|PC|1|2|3|4|5|6|7|8|9|10|11|12| 
|A|100|||||||||||| 
|Etc.| 

我回答以下問題:

(let [grouped (group-by (apply juxt [:month]) monthly-sales)] 
     (apply str (interpose "\n" 
    (for [k (distinct (map :pc rows))] 
      (str "|" k "|" (clojure.string/join "|" 
     (for [n (range 1 13)] 
       (get (first (filter #(= (:pc %) k) (get grouped [n]))) :sale)))))))))))) 

基本上我通過分組的所有值月(分組注意,由於「應用juxt」,可以鍵入多於1個鍵),這是該列的關鍵。做到這一點,我推斷了pc的獨特價值,這將是該行的關鍵。休息應該是自我解釋。

你認爲這是明確的clojurian設計?它能更有效率和清晰嗎?

相關鏈接: http://pramode.net/clojure/2010/06/01/lazy-sequences-in-clojure/

回答

3

地道Clojure庫(如clojure.java.jdbc)將爲這些長列表懶惰seqs。這意味着你只需要足夠的內存來包含單行加上通常的加載clojure和庫的開銷 - 假設你從文件或數據庫獲取數據並將其寫入流/ db/whatever並且不將它全部保存記憶。

至於變換你要求,給予行的序列(圖)稱爲結果集,這樣的:

(interpose "\n" 
    (map (fn [row] 
    (clojure.string/join "|" (map row [:consumer :product ...])) 
    result-set))) 

會給你一個懶序列,你可以只轉儲到文件來產生類似於|的內容你想分離的數據。

附錄:作爲「快」 - 除非你的存儲設置是不尋常的,這很可能比你的存儲顯著更快的I/O - 這是直截了當。

0

在這篇文章中沒有跡象表明要通過處理此數據集來達到什麼最終目標。至少,我不認爲主要想法可能會將1GB的數據放入HTML表格中。因此,沒有任何信息可以說明如何最好地實現這一目標。重新排列相同的數據不會給出任何有意義的結果,或者改變您之後要執行的操作的內存或訪問要求。

首先,你顯示爲「基地」的數據看起來可能是從連接查詢的結果至少有三個關係表(如果得到適當的歸一化)。通過SQL直接從這些表中獲取信息可能會更加高效,在Clojure本身處理之前已經減少了信息量,過濾或排序。

如果不是的話,正確標準化數據並將其存儲在數據庫中可能是一種選擇,但一切都取決於你想在年底的數據做什麼。