2016-04-15 33 views
2

我正試圖想出一個功能性解決方案來解決由交替設置和數值組成的自定義數據結構中的重複項。考慮自定義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中的高階函數。

感謝。

+1

你可以分享你的循環/復發解決方案嗎? – jmargolisvt

+0

對的順序是否重要?否則,您可以將數據保存爲從關鍵字集合到序列(矢量?)數字的映射。 – Thumbnail

回答

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])) 
      [])) 
5
(reduce 
    (fn [acc [k v]] 
    (update acc k (fnil + 0) v)) 
    {} 
    (partition 2 a)) 

首先,劃分你的序列與partition鍵值對,然後reduce那些對。訣竅是使用fnil,它將替代nil,該密鑰尚未添加到acc,但值爲0

這就給了你一張地圖:

{#{:a} 0.5, #{:b} 0.4, #{:b :a} 0.1} 

如果你需要它作爲價值的平序列,你可以通過它通過seqflatten:(只是爲了好玩

(->> 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) 
+0

我從來沒有用過'fnil'。謝謝你指出。十分優雅。 – endbegin

+0

不客氣:)。我忽略了你需要一系列值,而不是地圖。我已經更新了我的答案。 –

+0

我知道我沒有把你的答案標記爲「接受」,但它是。希望我可以將兩者都視爲已被接受。我做了一個'(變成[](seq(flatten)...)'來最後得到一個向量 – endbegin

4

多一個變種,因爲reduce版本顯然有更好的表現):

(->> a 
    (partition 2) 
    (group-by first) 
    (map (fn [[k v]] [k (apply + (map second v))])) 
    (reduce into []))