2011-10-19 17 views
8

मान लीजिए मैं एक आंतरिक संरचना, कुछ इस तरह है:clojure नाम बदलने कुंजी

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

और मैं नक्शे में प्रमुख नामों को बदलने की जरूरत है। मैं इस तरह शीर्ष स्तर कुंजियों को बदलने के कर सकते हैं:

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

लेकिन मुझे यकीन है डेटा संरचना में और अधिक गहराई से नेस्टेड कुंजी का नाम बदलने के लिए कैसे नहीं कर रहा हूँ (जैसे कि मैं नाम बदलना चाहते हैं: desc क्षेत्र के लिए: वर्णन)।

मैं बहुत यकीन है कि ज़िपर के जवाब हैं, लेकिन काफी को समझ नहीं सकता कि यह कैसे करना है, या कर रहा हूँ वहाँ एक और अधिक सरल तरीका है।

उत्तर

7

ब्रायन छिद्रान्वेषी के समाधान के रूप में एक ही छोड़कर पैदल दूरी पर नाम स्थान पहले से ही इस उद्देश्य के लिए एक विशेष समारोह है: कई मामलों में, आप update-in साथ एक आंतरिक संरचना में अपडेट कर सकते हैं। सभी स्तरों पर सभी कुंजियां बदल दी जाती हैं, चाहे वे किसी भी प्रकार के संग्रह या सीईसी के अंदर घोंसले हों।

(: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, सामान्य रूप में एक बहुत भारी हथौड़े है। ,

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

क्या यह तब भी काम करता है जब मेरे पास डेटा संरचना में वैक्टर और मानचित्र का संयोजन होता है? असल में मेरे पास एक जेसन दस्तावेज़ है जिसे क्लोजर डेटा स्ट्रक्चर में परिवर्तित कर दिया गया है और मुझे इसे पास करने से पहले इसे थोड़ा सा बदलने की जरूरत है। यह बेहतर दिखता है क्योंकि मैं यह सुनिश्चित करना चाहता हूं कि मैं गलती से कुछ नाम बदल रहा हूं। – Kevin

+0

मैं मेरी समस्या लगता है (उम्मीद है कि समझ में आता है ...) – Kevin

+0

क्यों की पैदल दूरी पर एक हथौड़े माना जाता है कि मैं पूरा पथ निर्दिष्ट करना चाहते हैं लेकिन मैं यह भी यह रास्ता साथ सभी वेक्टर सूचकांक पर लागू करना चाहते है? क्या यह 'सभी या कुछ भी नहीं' दृष्टिकोण, प्रदर्शन विचार, या पूरी तरह से कुछ और के कारण है? – NielsK