首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >通过Clojure透视数据

通过Clojure透视数据
EN

Stack Overflow用户
提问于 2012-07-12 02:20:21
回答 2查看 805关注 0票数 1

我有一个从db返回的地图集合,数据布局如下

代码语言:javascript
复制
[{:date "2012-6-6" :region "US" :status 1}
 {:date "2012-6-10" :region "UK" :status 2}
 {:date "2012-6-10" :region "US" :status 1}
 {:date "2012-6-11" :region "UK" :status 3}]

我想要旋转/转置数据,这样我就可以得到

代码语言:javascript
复制
[{:date "2012-6-6" :US 1 :UK 0}
 {:date "2012-6-10" :US 1 :UK 2}
 {:date "2012-6-11" :US 0 :UK 3}]
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2012-07-13 00:31:49

以下是您可以在描述问题时具体解决此问题的一种方法--如中所示,没有任何一般性:

代码语言:javascript
复制
(def data
  [{:date "2012-6-6" :region "US" :status 1}
   {:date "2012-6-10" :region "UK" :status 2}
   {:date "2012-6-10" :region "US" :status 1}
   {:date "2012-6-11" :region "UK" :status 3}]

=> (map (fn [[date data-points]]
          (apply assoc {:date date}
                 (mapcat (juxt (comp keyword :region)
                               :status)
                         data-points)))
        (group-by :date
                  data)))
=> ({:US 1, :date "2012-6-6"}
    {:US 1, :UK 2, :date "2012-6-10"}
    {:UK 3, :date "2012-6-11"})

它的工作方式是按日期对数据进行分组,然后向下映射一个函数(我将在稍后讨论该函数)。group-by通过对序列中的元素调用某个函数,并对该函数具有相等返回值的元素进行分组,从而对这些元素进行分组。它生成一个散列映射,其中每个唯一返回值都是一个键,映射中的每个值都是返回该值的原始序列中的元素序列。例如,以下是按日期分组的数据:

代码语言:javascript
复制
{"2012-6-6" [{:status 1
              :date "2012-6-6"
              :region "US"}]
 "2012-6-10" [{:status 2
               :date "2012-6-10"
               :region "UK"}
              {:status 1
               :date "2012-6-10"
               :region "US"}]
 "2012-6-11" [{:status 3
               :date "2012-6-11"
               :region "UK"}]}

这就是group-by的工作原理。现在,映射到此分组数据的函数将把date绑定到每个序列的第一个元素,并将data-points绑定到每个序列的第二个元素。我们将(apply assoc {:date date} ...)到数据点的“重组”,其中在:region的价值现在是:status的价值的关键字。“重构”是由mapcat-ing向下data-points使用一个函数进行的,该函数是在每个数据点上调用(comp keyword :region):statusjuxt

为了有希望地阐明这个juxt-ed函数正在做什么,我给出了如果它被写出来,等效函数将是什么样子:

代码语言:javascript
复制
(defn above-juxted-fn
  [data-point]
  [(keyword (:region data-point))
   (:status data-point)])

现在,实际上这并不是一个完整的解决方案,因为您似乎希望包括所有可能的区域作为关键字,如果没有该区域和日期的数据,则该值为零。但是,使用上面的解决方案返回的结果,每当您对任何数据点执行(get region-key-here)时,您都可以改为执行(get region-key-here 0),这样,如果查找未能找到给定的区域键,则缺省值将为零。

另一件事:如果你正在处理大量数据,我不相信这是一种特别快的方法(也许其他人在这里会有更准确和详细的建议)。我写它的目的是简单性和简约性。

此外,正如我在上面所说的,它没有一般性。至于通用性,我们可以通过将其建模为一个带有三个参数的函数来改变这一点: 1)一个映射序列2)一个分组键和3)一个"new- key -at“"new-val-at”对序列,我称之为重构规范(例如,在上面,这将是[:region :status])。如下所示:

代码语言:javascript
复制
(defn group-and-restructure
  [data grouping-key & restructuring-specs]
  (let [grouped-data (group-by grouping-key
                               data)
        restructuring-fn (apply juxt
                                (mapcat (fn [[k1 k2]]
                                          [(comp keyword k1)
                                           k2])
                                        restructuring-specs))]
    (map (fn [[grouping-k-value
               data-points]]
           (apply assoc {grouping-key grouping-k-value}
                  (mapcat restructuring-fn
                          data-points)))
         grouped-data)))

=> (group-and-restructure
     [{:date "2012-6-6" :region "US" :status 1}
      {:date "2012-6-10" :region "UK" :status 2}
      {:date "2012-6-10" :region "US" :status 1}
      {:date "2012-6-11" :region "UK" :status 3}]
     :date
     [:region :status])
=> ({:US 1, :date "2012-6-6"}
    {:US 1, :UK 2, :date "2012-6-10"}
    {:UK 3, :date "2012-6-11"})

这与上面的具体解决方案非常相似。主要区别在于,重构规范被转换为一个函数,当mapcat-ted data-points关闭时,该函数将返回一个新的密钥/val对序列,该序列将被assoc-ed到新的返回数据中。最好的部分是,这个函数允许您灵活地重新构造数据。例如,您可以按:region分组并按[:date :status]重构,如下所示:

代码语言:javascript
复制
=> (group-and-restructure
     [{:date "2012-6-6" :region "US" :status 1}
      {:date "2012-6-10" :region "UK" :status 2}
      {:date "2012-6-10" :region "US" :status 1}
      {:date "2012-6-11" :region "UK" :status 3}]
     :region
     [:date :status])
=> ({:2012-6-10 1, :2012-6-6 1, :region "US"}
    {:2012-6-11 3, :2012-6-10 2, :region "UK"})
票数 4
EN

Stack Overflow用户

发布于 2012-07-12 15:38:51

这不能处理缺失区域需要0的情况。

代码语言:javascript
复制
(->> (group-by :date DB-DATA)
     (map (fn [[_ coll]]
            (apply merge (map (fn [{:keys [status date region]}]
                                {:date date (keyword region) status})
                              coll))))
     vec)
=> [{:date "2012-6-6", :US 1} {:US 1, :date "2012-6-10", :UK 2} {:date "2012-6-11", :UK 3}]
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/11438918

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档