2011-11-21 54 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本身处理之前已经减少了信息量,过滤或排序。

如果不是的话,正确标准化数据并将其存储在数据库中可能是一种选择,但一切都取决于你想在年底的数据做什么。