我正在尝试提出一种功能性解决方案,以解释由交替集和数值组成的自定义数据结构中的重复项。
一个例子:
(def a [#{:a} 0.1 #{:b} 0.3 #{:a :b} 0.1 #{:a} 0.3 #{:b} 0.1 #{:a} 0.1])
我想添加与重复集相对应的值以产生
[#{:a} 0.5 #{:b} 0.4 #{:a :b} 0.1]
我可以使用loop/recur
执行此操作,但想知道是否有一种方法在Clojure中使用高阶函数。
感谢。
答案 0 :(得分:5)
(reduce
(fn [acc [k v]]
(update acc k (fnil + 0) v))
{}
(partition 2 a))
First, partition your sequence into key-value pairs with partition
and then reduce
those pairs. The trick is to use fnil
which will replace nil
for keys that hasn't been added to acc
yet with value 0
.
That gives you a map:
{#{:a} 0.5, #{:b} 0.4, #{:b :a} 0.1}
If you need it as the flat sequence of values you can pass it through seq
and flatten
:
(->> a
(partition 2)
(reduce
(fn [acc [k v]]
(update acc k (fnil + 0) v))
{})
(apply concat)
(into []))
;; => (#{:a} 0.5 #{:b} 0.4 #{:b :a} 0.1)
答案 1 :(得分:4)
另一个变体(只是为了好玩,因为reduce
版本显然有更好的性能):
(->> a
(partition 2)
(group-by first)
(map (fn [[k v]] [k (apply + (map second v))]))
(reduce into []))
答案 2 :(得分:1)
我会将源矢量折叠成一个地图,其中键作为数值的聚合,然后将其展开回矢量。
(->> a
(partition 2)
(reduce (fn [acc [k v]]
(if (get acc k)
(update acc k (partial + v))
(assoc acc k v)))
{})
(reduce (fn [acc [k v]]
(into acc [k v]))
[]))