2011-10-19 66 views
8

假設我有一個嵌套的結構,這樣的事情:Clojure的命名密鑰

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

我需要的地圖,爲鍵名。我可以將頂級鍵這樣的:

(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執行嵌套結構更新:

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