2016-04-19 3 views
1

Wie kann ich eine Funktion über einen Vektor von Karten (die auch Vektoren von Karten enthalten) zuordnen, um alle Punkte aus Schlüsselwortnamensräumen zu entfernen?alle Schlüsselwörter in der Sammlung ändern, Punkte aus dem Namespace entfernen und durch einen Gedankenstrich ersetzen

So gegeben:

[{:my.dotted/namespace "FOO"} 
{:my.nested/vec [{:another.dotted/namespace "BAR" 
        :and.another/one "FIZ"}]}] 

wird:

[{:my-dotted/namespace "FOO"} 
{:my-nested/vec [{:another-dotted/namespace "BAR" 
        :and-another/one "FIZ"}]}] 

Antwort

5

Klingt wie ein Job für clojure.walk!

Sie können die gesamte Datenstruktur durchqueren und eine Umwandlungsfunktion (transform-map in meiner Version) auf allen Unterformen, die eine Schlüssel der Karte schaltet gelten (hier mit dotted->dashed), wenn es ein trifft.

(require '[clojure 
      [walk :as walk] 
      [string :as str]]) 

(defn remove-dots-from-keys 
    [data] 
    (let [dotted->dashed #(-> % str (str/replace "." "-") (subs 1) keyword) 
     transform-map (fn [form] 
         (if (map? form) 
          (reduce-kv (fn [acc k v] (assoc acc (dotted->dashed k) v)) {} form) 
          form))] 
    (walk/postwalk transform-map data))) 
+0

Dank, das absolut, was ich brauche - ich 'gehen' erinnern. – Zuriar

2

Ich bin teilweise auf clojure.walk für diese Art von Jobs. Die Grundidee besteht darin, Funktionen zu erstellen, die die gewünschte Ersetzung ausführen, wenn sie einen Wert erhalten, der ersetzt werden soll. Andernfalls wird das Argument zurückgegeben. Dann übergeben Sie diese Funktion und eine Struktur an postwalk (oder prewalk) und es geht die Datenstruktur für Sie, wobei jeder Wert durch den Rückgabewert der Funktion ersetzt wird.

(ns replace-keywords 
    (:require [clojure.walk :refer [postwalk]] 
      [clojure.string :refer [join]])) 

(defn dash-keyword [k] 
    (when (keyword? k) 
    (->> k 
     str 
     (map (some-fn {\. \-} identity)) 
     rest 
     join 
     keyword))) 

(dash-keyword :foo.bar/baz) 
;; => :foo-bar/baz 


(defonce nested [ {:my-dotted/namespace "FOO"} 
        {:my-nested/vec [ {:another-dotted/namespace "BAR" 
            :and-another/one "FIZ"} ]}]) 

(postwalk (some-fn dash-keyword identity) nested) 
;; =>[{:my-dotted/namespace "FOO"} 
;; {:my-nested/vec [{:another-dotted/namespace "BAR", 
;;      :and-another/one "FIZ"}]}] 

Zweimal hier verwende ich die Kombination von some-fn mit einer Funktion, die einen Ersatz oder nil zurückzugibt, was eine nette Art und Weise sein kann mehrere „Ersetzungsregeln“ zu kombinieren - wenn keine des früheren Feuers dann identity sein Der erste, der einen Wert ungleich nil zurückgibt und das Argument wird nicht geändert.

(require '[clojure.string :as str]) 

(defn dot->dash [maps] 
    (mapv #(into {} (for [[k v] %] 
        [(keyword (str/replace (namespace k) "." "-") (name k)) 
        (if (vector? v) (dot->dash v) v)])) 
     maps)) 

Beispiel:

2

Dieses Problem kann auch ohne clojure.walk gelöst werden

(dot->dash [{:my.dotted/namespace "FOO"} 
      {:my.nested/vec [{:another.dotted/namespace "BAR" 
           :and.another/one "FIZ"}]}]) 
;=> [{:my-dotted/namespace "FOO"} 
; {:my-nested/vec [{:another-dotted/namespace "BAR" 
;      :and-another/one "FIZ"}]}] 
Verwandte Themen