我需要一种非常快速有效的方法来“转置”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))))))))))))
基本上我按月对所有值进行分组(分组,注意它可以通过“apply juxt”键入多于1个键),这是该列的关键。完成后,我推断pc的唯一值,这将是行的关键。休息应该是自我解释的。
您认为这是明确的clojurian设计吗?它可以更有效和清晰吗?
有用的链接: http://pramode.net/clojure/2010/06/01/lazy-sequences-in-clojure/
答案 0 :(得分:3)
习惯性的clojure库(如clojure.java.jdbc)将这些长列表作为惰性seq提供。这意味着你只需要足够的内存来包含一行以及加载clojure和库的通常开销 - 只要你从文件或数据库中获取数据并将其写入流/ db /中,而不是将其全部保存在存储器中。
至于你要求的变换,给定一个名为result-set的行(map),如:
(interpose "\n"
(map (fn [row]
(clojure.string/join "|" (map row [:consumer :product ...]))
result-set)))
将为您提供一个懒惰的seq,您可以将其转储到文件中以生成类似于|的东西你想要的分开的数据。
附录:至于“快速” - 除非你的存储设置不常见,否则这可能比你的存储I / O快得多 - 而且它很直接。
答案 1 :(得分:0)
本文中没有任何内容表明您希望通过处理此数据集实现最终目标。至少,我认为主要想法可能是将1GB的数据放入HTML表格中。因此,没有信息可以给出如何最好地实现这一点。只需重新排列相同的数据就不会产生任何有意义的结果,也不会改变您之后要执行的操作的内存或访问要求。
首先,您显示为“基础”数据的内容看起来可能是至少三个关系表上的联接查询的结果(如果已正确规范化)。通过SQL直接从这些表中获取信息可能更有效,在Clojure本身处理之前已经减少了信息量,过滤或排序。
如果不是,那么正确地将数据标准化并将其存储在数据库中可能是一种选择,但所有这些都取决于您最终想要对数据做什么。