2011-08-26 90 views
8

我有一个看起来像这样GROUP BY和聚集在地图上的矢量 - Clojure的

(def a [{:firmAccount "MSFT" :Val 10 :PE 3 } 
{:firmAccount "MSFT" :Val 15 :PE 4} 
{:firmAccount "GOG" :Val 15 :PE 3} 
{:firmAccount "YAH" :Val 8 :PE 1}]) 

数据我想组通过:firmAccount再总结的:瓦尔和:PE对于每个企业帐户,并获得像

[{:firmAccount "MSFT" :Val 25 :PE 7} 
    {:firmAccount "GOG" :Val 15 :PE 3}  
    {:FirmAccount "YAH" :Val 8 :PE 1}] 

这实在是一件微不足道的小事,并在SQL我就别想两次,但因为我学习的Clojure请多多包涵

回答

8

Clojure.core有一个内置组,按功能。这个解决方案由于地图中的文本和整型val的存在而变得有点丑陋。

(for [m (group-by :firmAccount a)] 
    (assoc (apply merge-with + (map #(dissoc % :firmAccount) (val m))) :firmAccount (key m))) 
+1

非常感谢。它适用于我,它非常简洁。此外,答案让我意识到如何在一个很棒的例子中使用assoc,merge-with,apply,dissoc,group-by和map。 – Ash

1

尝试创建地图的新地图数组或地图与同结构体。如果:公司帐户存在,您可以编写一个函数将这些元素添加到这个新地图中,并将这些字段相加。也许这样的地图?

(def a {"MSFT" {:Val 25 :PE 7 } 
    "GOG" {:Val 15 :PE 3} 
    "YAH" {:Val 8 :PE 1}}) 

有了这样一个个性化的附加功能:

(add-to-map [element map] 
    (if (contains? (find-name element)) 
    {map (add-fields element (find (find-name element)))} 
    {map element})) 
+0

好吧,如果你使用Add功能我在这里勾勒出你不需要改变结构。请使用这个想法。 –

+0

由于问题中的数据结构,此更改是必需的。您在回答中使用的结构是要求的答案,而不是必需的输入。 – mac

5

以及物品是否完整下面是一个使用地图的替代版本:

(map (fn [[firmAccount vals]] 
    {:firmAccount firmAccount 
    :Val (reduce + (map :Val vals)) 
    :PE (reduce + (map :PE vals))}) 
    (group-by :firmAccount a)) 
+0

有趣,一个。非常感谢 – Ash