我有一个从db返回的地图集合,数据布局如下
[{: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 "2012-6-6" :US 1 :UK 0}
{:date "2012-6-10" :US 1 :UK 2}
{:date "2012-6-11" :US 0 :UK 3}]发布于 2012-07-13 00:31:49
以下是您可以在描述问题时具体解决此问题的一种方法--如中所示,没有任何一般性:
(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通过对序列中的元素调用某个函数,并对该函数具有相等返回值的元素进行分组,从而对这些元素进行分组。它生成一个散列映射,其中每个唯一返回值都是一个键,映射中的每个值都是返回该值的原始序列中的元素序列。例如,以下是按日期分组的数据:
{"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)和:status的juxt。
为了有希望地阐明这个juxt-ed函数正在做什么,我给出了如果它被写出来,等效函数将是什么样子:
(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])。如下所示:
(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]重构,如下所示:
=> (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"})发布于 2012-07-12 15:38:51
这不能处理缺失区域需要0的情况。
(->> (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}]https://stackoverflow.com/questions/11438918
复制相似问题