2016-07-20 27 views
1

Ich habe eine Liste von KartenHinzufügen von Schlüssel- Wert-Paaren Karten in einer Liste von Karten aus einer anderen Liste von Karten in clojure

({:path "first" :size "1 gb"} 
    {:path "second" :size "500 mb"} 
    ...) 

und eine weitere Liste von Karten

({:path "first" :size "1 gb" :date "1"} 
    {:path "second" :size "500 mb" :date "1"} 
    {:path "first" :size "0.9 gb" :date "2"}... 
    {:path "second" :size "400 mb" :date "2"}... 
...) 

Ich mag holen Sie sich die erste Liste der Karten zu etwas verwandelt wie

({:path "first" :sizeon1 "1 gb" :sizeon2 "0.9 gb"...} 
    {:path "second" :sizeon1 "500 mb" :sizeon2 "400 mb"...} 
    ....) 

ich bin ein noob Clojure und eine harte Zeit, dies zu tun haben. Kannst du mir bitte helfen?

+0

in Ihrem Beispiel brauchen Sie nicht wirklich erste Liste, weil es Daten in der zweiten dupliziert ist. Ist es immer wahr, oder gibt es Fälle, wo ein Pfadwert in der ersten Liste vorhanden ist und in der zweiten nicht vorhanden ist oder umgekehrt? Wenn ja, was ist das erwartete Ergebnis für diese Fälle? – leetwinski

+0

ja das ist immer wahr. Ich brauche nur eine neue Liste mit dem gewünschten Ergebnis aus der zweiten Liste. Die zweite Liste ist nach Datum sortiert ... alle Einträge mit Datum "1" zuerst, dann "2" usw. (bearbeitet) .. Wie kann es gemacht werden? Kannst du bitte Superkondustrs Antwort sehen und meinen Kommentar beantworten? – user3083633

Antwort

2

Was würde ich tun, ist die resultierende Datenstruktur zu überdenken: Ich weiß nicht, wie würden Sie möglicherweise die resultierende Sammlung verwenden, aber die Benennung Schlüssel :sizeonX, vor allem, wenn es potenziell variable Menge der registrierten Daten oder einige von ihnen fehlen vielleicht (wie zum Beispiel, wenn Sie Termine 1 und 3 für den ersten Weg haben, und 1235 für die zweite) führt zu einem Durcheinander von unvorhersehbar benannten Schlüsseln in resultierenden Karten, die es Art und Weise machen würde schwieriger, wenn es darum geht, diese Schlüssel abzurufen. ich es sieht so aus, dass es besser wäre, diese Struktur zu verwenden:

{:path "first" :sizes {"1" "500" "2" "1g" "10" "222"}} 

so Größen dieser Karte leicht iterativ und verarbeitet wird.

das ist, wie würde ich das tun:

(def data '({:path "first" :size "1 gb" :date "1"} 
      {:path "first" :size "0.9 gb" :date "3"} 
      {:path "second" :size "500 mb" :date "1"} 
      {:path "second" :size "700 mb" :date "2"} 
      {:path "second" :size "400 mb" :date "3"} 
      {:path "second" :size "900 mb" :date "5"})) 

(map (fn [[k v]] {:path k 
        :sizes (into {} (map (juxt :date :size) v))}) 
    (group-by :path data)) 

;; ({:path "first", :sizes {"1" "1 gb", "3" "0.9 gb"}} 
;; {:path "second", :sizes {"1" "500 mb", 
;;       "2" "700 mb", 
;;       "3" "400 mb", 
;;       "5" "900 mb"}}) 

Update

aber wie Sie noch die Struktur von der Frage brauchen, ich es so tun würde:

(map (fn [[k v]] 
     (into {:path k} 
      (map #(vector (keyword (str "sizeon" (:date %))) 
          (:size %)) 
       v))) 
    (group-by :path data)) 

;;({:path "first", :sizeon1 "1 gb", :sizeon3 "0.9 gb"} 
;; {:path "second", 
;; :sizeon1 "500 mb", :sizeon2 "700 mb", 
;; :sizeon3 "400 mb", :sizeon5 "900 mb"}) 

das ist im Grunde ähnlich zu @superkonduktr Variante.

+0

Es tut mir leid, aber ich brauche sie in Form von Schlüsseln, da sie tatsächlich Spalten in einer Tabelle sind. Gibt es eine Möglichkeit, dies in ein solches Formular zu konvertieren? Oder eine andere Art und Weise? – user3083633

+0

aktualisiert meine Antwort – leetwinski

+0

Danke! Es funktioniert jetzt – user3083633

2

Alles wird klar, wenn Sie Ihre Aufgabe in kleinere Teile zerlegen.

Zunächst definiert einen Helfer diese :sizeon1 Schlüssel im Ergebnisdatensatz zu erstellen:

(defn date-key 
    [date] 
    (keyword (str "sizeon" date))) 

Als nächstes wollen Sie eine Sammlung von einzelnen Pfaddaten in aggregierter Karte zu reduzieren, wie eine Sammlung unter der Annahme, sieht aus, als Sie beschrieben:

[{:path "first" :size "1 gb" :date "1"} 
{:path "first" :size "0.9 gb" :date "2"} 
;; ... 
] 

reduce ist nur das Werkzeug dafür:

(defn reduce-path 
    [path-data] 
    (reduce 
    ;; A function that takes an accumulator map and an element in the collection 
    ;; from which you take date and size and assoc them under the appropriate keys 
    (fn [acc el] 
     (let [{:keys [date size]} el] 
     (assoc acc (date-key date) size))) 
    ;; A starting value for the accumulator containing the common path 
    ;; for this collection 
    {:path (:path (first path-data))} 
    ;; The collection of single path data to reduce 
    path-data)) 

Schließlich nehmen Sie das Raw-Dataset mit verschiedenen Pfaden, partitionieren Sie es nach Pfad und ordnen Sie ihm die reduce-path-Funktion zu.

(def data 
    [{:path "first" :size "1 gb" :date "1"} 
    {:path "first" :size "0.9 gb" :date "2"} 
    {:path "second" :size "500 mb" :date "1"} 
    {:path "second" :size "400 mb" :date "2"}]) 

(->> data 
    (partition-by :path) 
    (map reduce-path)) 

Beachten Sie, dass dieser Code geht davon aus, dass Ihre anfängliche data Sammlung bereits von :path sortiert ist. Andernfalls funktioniert partition-by nicht wie erwartet, und die Daten müssen entsprechend vorbereitet werden.

+0

Vielen Dank! Wie Sie gesagt haben Partition funktioniert nicht, wenn Sammlung nicht sortiert ist nach: Pfad meine Daten sind so, dass alle Karten mit: Datum "1" zuerst, dann: Datum "2" und so weiter ... Können Sie mir bitte was sagen in so einer Situation tun? – user3083633

+1

In diesem Fall sollten Sie die Zeile '(partition-by: path)' durch zwei Zeilen ersetzen: '(group-by: path)' und 'vals'. Dies hat den gleichen Effekt, da "group-by" Elemente in eine Map gruppiert. Werte sind Sammlungen ähnlich denen von "partition-by". – leetwinski

+1

Zusätzlich zu @ leetwinskis Vorschlag ist es erwähnenswert, dass Ihre Daten nicht sinnvoll sind (idealerweise numerisch), um die Sortierung durchzuführen. Dann können Sie '(sort-by: sortierbare Schlüsselsammlung)' verwenden, um die richtige Reihenfolge sicherzustellen, bevor Sie die Sammlung der reduzierenden Funktion zuführen. Einige Anwendungsbeispiele finden Sie unter https://clojuredocs.org/clojure.core/sort-by! – superkonduktr

2
(def data '({:path "first" :size "1 gb" :date "1"} 
      {:path "second" :size "500 mb" :date "1"} 
      {:path "first" :size "0.9 gb" :date "2"} 
      {:path "second" :size "400 mb" :date "2"})) 

(defn- reduce-group [g] 
    (reduce (fn [acc m] (assoc acc 
          (keyword (str "sizeon" (:date m))) 
          (:size m))) 
      (first g) g)) 

(let [groups (group-by :path data)] 
    (map reduce-group (vals groups))) 
+1

ich denke, es ist falsch, weil die op wahrscheinlich Schlüssel nach ihrem ': date'-Wert (möglicherweise gibt es mehr. (': Size3' etc.) – leetwinski

+1

Ah, ich missverstanden dann. Ich habe meine Antwort. –