2011-10-19 6 views
8

私は、このような何か入れ子構造があるとします。Clojureのリネーム・キー

{:data1 
    {:categories [ 
     {:name "abc" :id 234 :desc "whatever"} 
     {:name "def" :id 456 :desc "nothing"}] 
    } 
    :data2 {...} 
    :data3 {...} 
} 

を私はマップ内のキー名を変換する必要があります。 (:DESCフィールドへ:記述言う私は名前を変更する)

(rename-keys mymap {:data1 :d1}) 

しかし、私はデータ構造に深くネストされたキーの名前を変更するかどうかはわかりません。私はこのようなトップレベルのキーを変換することができます。

私はかなりジッパーが答えているが、それをどうやって行うか、またはもっと簡単な方法があるかどうかは分かりません。

答えて

7

、歩行名前空間はすでに、この目的のために特定の機能を持っている点が異なります。どんな種類のコレクションやseqの中に入れ子になっていても、すべてのレベルのすべてのキーが変更されます。

(:use 'clojure.walk) 

(def x 
    {:data1 
    {:categories 
    [{:desc "whatever", :name "abc", :id 234} 
    {:desc "nothing", :name "def", :id 456}]}, 
    :data2 
    {:categories 
    [{:desc "whatever", :name "abc", :id 234} 
    {:desc "nothing", :name "def", :id 456}]}}) 

(postwalk-replace {:desc :something} x) 

{:data1 
{:categories 
    [{:something "whatever", :name "abc", :id 234} 
    {:something "nothing", :name "def", :id 456}]}, 
:data2 
{:categories 
    [{:something "whatever", :name "abc", :id 234} 
    {:something "nothing", :name "def", :id 456}]}} 
+1

うわー...超クール –

3

:descキーの名前を、ネストのレベルに関係なくすべて変更したい場合は、これが機能する場合があります。特定のネストレベルで:descキーの名前を変更したい場合は、少し洗練されたものが必要です。

これは、最初の引数がマップでない場合、clojure.set/rename-keysは現在何も実行していないため(最初の引数はそのまま)戻ります。

user> (require '[clojure [set :as set] [walk :as walk]]) 
nil 

user> (def x {:data1 
       {:categories 
       [{:desc "whatever", :name "abc", :id 234} 
       {:desc "nothing", :name "def", :id 456}]}, 
       :data2 
       {:categories 
       [{:desc "whatever", :name "abc", :id 234} 
       {:desc "nothing", :name "def", :id 456}]}}) 
#'user/x 

user> (walk/postwalk #(set/rename-keys % {:desc :description :id :ID}) x) 
{:data1 
{:categories 
    [{:name "abc", :ID 234, :description "whatever"} 
    {:name "def", :ID 456, :description "nothing"}]}, 
:data2 
{:categories 
    [{:name "abc", :ID 234, :description "whatever"} 
    {:name "def", :ID 456, :description "nothing"}]}} 
nil 
+0

これはかなりいいです。私はまだそれが私の状況のた​​めに働くかどうかはわかりませんが(どちらかというと)どちらかの方法で涼しいです。 – Kevin

5

postwalkあなたがそれを必要とするかもしれないように、それはあなたの元の質問から見えますが、一般的にはかなり重いハンマーです。多くの場合、あなたはupdate-inと入れ子構造で更新を行うことができます。

ブライアンCarperの溶液と同じ
user> (let [m {:foo {:deep {:bar 1 :baz 2}}}] 
     (update-in m [:foo :deep] clojure.set/rename-keys {:baz :periwinkle})) 
{:foo {:deep {:periwinkle 2, :bar 1}}} 
+0

これは、データ構造にベクトルとマップの組み合わせがある場合にも機能しますか?基本的に私はclojureデータ構造に変換されたjsonドキュメントを持っており、それを渡す前にそれを少し変換する必要があります。これは、私が誤って何かの名前を変更していないことを確認したいので、望ましいと思われます。 – Kevin

+0

私は自分の問題は完全なパスを指定したいと思っていますが、途中のすべてのベクトルインデックスにも適用したいと思っています(うまくいけば...) – Kevin

+0

なぜ歩くのがスレンダーであると思われますか?これは、「すべてかどうか」のアプローチ、パフォーマンスの検討事項、または完全に他の何かのためですか? – NielsK

関連する問題