Vector 计算自定义clojure向量中的重复项
我试图提出一个函数式解决方案来解释由交替集合和数值组成的自定义数据结构中的重复项 例如:Vector 计算自定义clojure向量中的重复项,vector,clojure,Vector,Clojure,我试图提出一个函数式解决方案来解释由交替集合和数值组成的自定义数据结构中的重复项 例如: (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中使用高阶函数 谢谢。我会将源向量折叠成一张地图,其中的键用作数值的聚
(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中使用高阶函数
谢谢。我会将源向量折叠成一张地图,其中的键用作数值的聚合,然后将其展开成向量
(->> 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]))
[]))
首先,使用partition
将序列划分为键值对,然后使用reduce
将这些键值对进行划分。诀窍是使用fnil
,它将取代nil
,用于尚未添加到acc
但值为0
的密钥
这会给你一张地图:
{#{:a} 0.5, #{:b} 0.4, #{:b :a} 0.1}
如果需要将其作为值的平面序列,可以通过seq
和flant
传递:
(->> 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)
还有一个变体(只是为了好玩,因为reduce
version显然有更好的性能):
你能分享你的循环/重现解决方案吗?对的顺序重要吗?如果没有,您可以将数据保存为从一组关键字到数字序列(向量?)的映射。我以前从未使用过
fnil
。谢谢你指出这一点。非常优雅。不客气:)。我忽略了你需要的是一系列的值,而不是一张地图。我已经更新了我的答案。我知道我没有将你的答案标记为“已接受”,但确实如此。但愿我能把两者都标为已接受。我做了一个(into[](seq(flatten)))
来得到最后的向量。展平
通常是个坏主意。在这种情况下(只有一个深度级别),最好使用(apply concat)
或(mapcat identity)
而不是(flatte)
。它还可以让您删除(seq)
来自的行there@leetwinski你说得对,让我加强我的回答。
(->> 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)
(->> a
(partition 2)
(group-by first)
(map (fn [[k v]] [k (apply + (map second v))]))
(reduce into []))