2016-07-20 11 views
0

Ich habe eine Sammlung von KartenGruppieren - nach einer Sammlung, die bereits nach Clojure gruppiert ist?

(def a '({:id 9345 :value 3 :type "orange"} 
     {:id 2945 :value 2 :type "orange"} 
     {:id 145 :value 3 :type "orange"} 
     {:id 2745 :value 6 :type "apple"} 
     {:id 2345 :value 6 :type "apple"})) 

ich den ersten von Wert gruppieren mag, nach Art gefolgt.

sollte Meine Ausgabe wie folgt aussehen:

{ 
    :orange [{ 
     :value 3, 
     :id [9345, 145] 
    }, { 
     :value 2, 
     :id [2935] 
    }], 
    :apple [{ 
     :value 6, 
     :id [2745, 2345] 
    }] 
} 

Wie würde ich dies tun in Clojure? Schätze deine Antworten.

Danke!

Edit:

Hier ist, was ich bisher hatte:

(defn by-type-key [data] 
    (group-by #(get % "type") data)) 

(reduce-kv 
    (fn [m k v] (assoc m k (reduce-kv 
          (fn [sm sk sv] (assoc sm sk (into [] (map #(:id %) sv)))) 
          {} 
          (group-by :value (map #(dissoc % :type) v))))) 
    {} 
    (by-type-key a)) 

Ausgang:

=> {"orange" {3 [9345 145], 2 [2945]}, "apple" {6 [2745 2345], 3 [125]}} 

Ich konnte nicht nur herausfinden, wie weiter verfahren ...

+0

@cfrick meinen ursprünglichen Beitrag Herausgegeben mit dem, was Lösung hatte ich bisher – Bala

Antwort

1

ich tun würde, die Transformation in zwei Stufen (reduzieren verwenden):

  • die ersten, die Werte
  • die zweite für Formating

Der folgende Code löst Ihr Problem sammeln :

(def a '({:id 9345 :value 3 :type "orange"} 
     {:id 2945 :value 2 :type "orange"} 
     {:id 145 :value 3 :type "orange"} 
     {:id 2745 :value 6 :type "apple"} 
     {:id 2345 :value 6 :type "apple"})) 

(defn standardise [m] 
    (->> m 
     ;; first stage 
     (reduce (fn [out {:keys [type value id]}] 
       (update-in out [type value] (fnil #(conj % id) []))) 
       {}) 
     ;; second stage 
     (reduce-kv (fn [out k v] 
        (assoc out (keyword k) 
          (reduce-kv (fn [out value id] 
             (conj out {:value value 
                :id id})) 
             [] 
             v))) 
        {}))) 

(standardise a) 
;; => {:orange [{:value 3, :id [9345 145]} 
;;    {:value 2, :id [2945]}], 
;;  :apple [{:value 6, :id [2745 2345]}]} 

Der Ausgang der ersten Stufe ist:

(reduce (fn [out {:keys [type value id]}] 
      (update-in out [type value] (fnil #(conj % id) []))) 
     {} 
     a) 
;;=> {"orange" {3 [9345 145], 2 [2945]}, "apple" {6 [2745 2345]}} 
+0

@ yuri-steinschreiber-Lösung für die erste Stufe ist wahrscheinlich das, was ich mit gehen würde, wie es besser vermittelt, was getan wird – zcaudate

2

Ihre Anforderungen sind ein wenig inkonsistent (oder eher irregul ar) - Sie verwenden :type Werte als Schlüsselwörter im Ergebnis, aber der Rest der Schlüsselwörter wird ausgeführt. Vielleicht müssen Sie das tun, um einige externe Formate zu erfüllen - andernfalls müssen Sie entweder den gleichen Ansatz wie bei :type verwenden oder dem Ergebnis ein neues Schlüsselwort hinzufügen, wie :group oder :rows und die ursprünglichen Schlüsselwörter beibehalten. Ich werde den ersten Ansatz für den Moment annehmen (aber siehe unten, ich an die Form erhalten wird, wie Sie es wollen,), so dass die endgültige Form der Daten ist wie

{:orange 
    {:3 [9345 145], 
     :2 [2945]}, 
:apple 
    {:6 [2745 2345]} 
} 

Es gibt mehr als einen Weg, um dorthin zu gelangen , hier ist der Kern eines:

(group-by (juxt :type :value) a) 

das Ergebnis:

{["orange" 3] [{:id 9345, :value 3, :type "orange"} {:id 145, :value 3, :type "orange"}], 
["orange" 2] [{:id 2945, :value 2, :type "orange"}], 
["apple" 6] [{:id 2745, :value 6, :type "apple"} {:id 2345, :value 6, :type "apple"}]} 

Jetzt werden alle Zeilen in Ihrer Sammlung durch die Tasten gruppiert sind Sie benötigen. Von diesem können Sie die gewünschte Form gehen und sagen, auf die Form erhalten über Sie

(reduce 
(fn [m [k v]] 
    (let [ks (map (comp keyword str) k)] 
     (assoc-in m ks 
       (map :id v)))) 
{} 
(group-by (juxt :type :value) a)) 

Die Grundidee ist durch die Tastenfolge der Zeilen gruppierten werden tun können (und das ist, was group-by und juxt tu,) und kombiniere dann reduce und assoc-in oder update-in, um das Ergebnis zu übertreffen.

Um genau die Form, die Sie beschrieben:

(reduce 
(fn [m [k v]] 
    (let [type (keyword (first k)) 
     value (second k) 
     ids (map :id v)] 
    (update-in m [type] 
       #(conj % {:value value :id ids})))) 
{} 
(group-by (juxt :type :value) a)) 

Es ist ein bisschen laut, und es könnte schwieriger sein, den Wald vor lauter Bäumen zu sehen - das ist, warum ich die Form vereinfacht, die Hauptidee zu markieren. Je regelmäßiger Ihre Formen sind, desto kürzer und regelmäßiger werden Ihre Funktionen - wenn Sie also die Kontrolle darüber haben, versuchen Sie es einfacher zu machen.

Verwandte Themen