2016-04-15 13 views
2

Ich versuche, eine funktionale Lösung zu finden, um Duplikate in einer benutzerdefinierten Datenstruktur zu berücksichtigen, die aus abwechselnden Mengen und numerischen Werten besteht.Accounting für Duplikate in einem benutzerdefinierten Clojure-Vektor

Ein Beispiel:

(def a [#{:a} 0.1 #{:b} 0.3 #{:a :b} 0.1 #{:a} 0.3 #{:b} 0.1 #{:a} 0.1]) 

Ich möchte die Werte hinzuzufügen entsprechenden Sätze duplizieren in

[#{:a} 0.5 #{:b} 0.4 #{:a :b} 0.1] 

führen Ich kann dies loop/recur mit tun, aber frage mich, ob es einen Weg gibt, die Anwendungen Funktion höherer Ordnung in Clojure.

Danke.

+1

Können Sie Ihre Loop-/Recurelösung teilen? – jmargolisvt

+0

Ist die Reihenfolge der Paare signifikant? Wenn nicht, können Sie die Daten als eine Karte von einem Satz von Schlüsselwörtern zu einer Folge (Vektor?) Von Zahlen halten. – Thumbnail

Antwort

1

Ich würde den Quellvektor in eine Karte mit Schlüsseln falten, die als Aggregate für numerische Werte dienen, und sie dann wieder in einen Vektor auffalten.

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

Zuerst Ihre Sequenz in Schlüssel-Wert-Paare mit partition partitionieren und dann reduce diese Paare. Der Trick besteht darin, fnil zu verwenden, das nil für Schlüssel ersetzen wird, die nicht zu acc noch mit Wert 0 hinzugefügt worden sind.

, dass Sie eine Karte gibt:

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

Wenn Sie es als die flache Folge von Werten müssen Sie es durch seq und flatten passieren kann:

(->> 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

Ich habe 'fnil' vorher noch nie benutzt. Danke, dass du darauf hingewiesen hast. Sehr elegant. – endbegin

+0

Gern geschehen :). Ich habe übersehen, dass Sie eine Folge von Werten benötigen, keine Karte. Ich habe meine Antwort aktualisiert. –

+0

Ich weiß, ich habe Ihre Antwort nicht als "akzeptiert" markiert, aber es ist. Ich wünschte, ich könnte beide als akzeptiert markieren. Ich habe ein '(in [] (seq (flatten) ...)' gemacht, um einen Vektor am Ende zu bekommen. – endbegin

4

eine weitere Variante (nur zum Spaß , denn reduce Version hat offensichtlich eine bessere Leistung):

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