Clojure - 格式化表格

时间:2014-03-03 16:00:02

标签: for-loop clojure formatting

我有一些XML文件,我已经成功地使用这些文件来产生一些针对每月时间段的计数,尽管我需要将其转换为稍微压缩它。我生成的列表是通过下面的一些for循环完成的(例如),我将它以下面的格式输出到表中:

LEVEL1 (for [forloop LVL4_records]
{
    :MONTH(get (split (:date forloop) #"-") 1)
    :LEVEL(:lvl forloop)
})

group-by-date(group-by :MONTH LEVEL1)

LEVEL1_2 (for [forloop2 group-by-date]
{
    :MONTH(:MONTH (first(second forloop2)))
    :LEVEL(:LEVEL(first (second forloop2)))
    :TOTAL(count (distinct (second forloop2)))
})

月 - LEVEL - COUNT

扬-------- --------- 01 10

扬-------- --------- 02 55

扬-------- --------- 03 112

二月-------- --------- 01 23

二月-------- --------- 02 30

二月-------- --------- 03 268


我想要做的是将其组织成一个月份不同且级别为主要标题的方式:


月 - 级别01 - 级别02--级别03

扬-------- 10 ------------ 55 ------------- 112

二月-------- 23 ------------ 30 ------------- 268


我猜我需要另一个循环来运行不同的级别,并使月份不同虽然我已经尝试了一些东西而且它们没有工作...到目前为止的代码在第一个表,所以在将数据重新格式化为第二种样式时,非常感谢这里的任何帮助。

2 个答案:

答案 0 :(得分:2)

从这里的数据中取出每组LEVEL

  

月 - LEVEL - COUNT

     

扬-------- --------- 01 10

     

扬-------- --------- 02 55

     

扬-------- --------- 03 112

     

二月-------- --------- 01 23

     

二月-------- --------- 02 30

     

二月-------- --------- 03 268

将它们转换为map,从:COUNT转换为:MONTH,然后使用您提供的格式通过这些地图打印表格。

e.g。地图应该是这样的

{:LEVEL 1 :DATA [{:MONTH "Jan" :COUNT 10}
                 {:MONTH "Feb" :COUNT 23}]
 :LEVEL 2 :DATA [{:MONTH "Jan" :COUNT 55}
                 {:MONTH "Feb" :COUNT 30}]
 :LEVEL 3 :DATA [{:MONTH "Jan" :COUNT 112}
                 {:MONTH "Feb" :COUNT 268}]

甚至

{1  {"Jan" 10
     "Feb" 23}
 2  {"Jan" 55
     "Feb" 30}
 3  {"Jan" 112
     "Feb" 268}

答案 1 :(得分:1)

这是一件很棘手的事情,但它是可行的。这就是我想出的:

(def by-level
  {1  {"Jan" 10, "Feb" 23}
   2  {"Jan" 55, "Feb" 30}
   3  {"Jan" 112, "Feb" 268}})

(def by-month
  (reduce (fn [table [level months]]
            (apply merge-with merge table (map (fn [[month count]] 
                                                 {month {level count}}) 
                                                months)))
          {}
          by-level))

; by-month =>
{"Jan" {3 112, 2 55, 1 10}, "Feb" {3 268, 2 30, 1 23}} 

(这是Albus回答的问题 - 他指出你的地图应该用关卡作为关键字排列,因为这就是你的XML文件的布局方式。)

reduce是for循环的功能对应物。我们在这里使用它来遍历我们的表(by-level)并从空地图by-month开始构建一个新表{}。在每次迭代中,我们选择by-level中的一个条目(例如,{1 {"Jan" 10, "Feb" 23}})并在每个月份计数对上使用map来返回{{1}形式的地图列表1}}(第一个数字是级别(1),第二个数字是计数(10))。然后我们{"Jan" {1 10}}将这些“月到水平/计数”映射到我们正在进行的表格中。一旦我们遍历原始地图中的每个“级别”,我们最终会得到每个月的地图到每个级别的次要地图及其数量。

merge”起初可能看起来有点奇怪。我们进行辅助apply merge-with merge操作的原因是我们正在处理嵌套映射。如果我们刚刚说过mergeapply merge"Jan"将被“覆盖”,每次传递到下一个级别,最后我们会有类似{{1}的内容}。使用"Feb",我们会这样做,以便如果{"Jan" {3 112}, "Feb" {3 268}}之类的密钥已经存在,我们merge-with "Jan"的现有值将带有新值 - 我们的值'重新使用merge之类的地图,所以我们不是替换我们拥有的值,而是通过合并新地图和新的等级/数组合来“添加”。

现在,您可以使用"Jan"从地图中获取单个值,例如:

{2 55}

或者您可以将get留出来,只需将地图本身用作函数:

(get (get by-month "Jan") 3) ;=> 112 (January, Level 3)