在自定义clojure向量中计算重复

时间:2016-04-15 14:20:21

标签: 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中使用高阶函数。

感谢。

3 个答案:

答案 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]))
             []))