2009-10-28 9 views
5

मैं क्लोजर नहीं हूं और यह पता लगाने का प्रयास कर रहा हूं कि यह कैसे करें।क्लोजर: मैं हैश-मैप में प्रविष्टियों के सबसेट में फ़ंक्शन कैसे लागू करूं?

मैं एक नया हैश-मैप बनाना चाहता हूं कि हैश-मैप में चाबियों के सबसेट के लिए तत्वों पर एक फ़ंक्शन लागू होता है। इसे करने का बेहतरीन तरीका क्या है?

(defn doto-map [ks f amap] 
    (into amap 
    (map (fn [[k v]] [k (f v)]) 
     (filter (fn [[k v]] (ks k)) amap)))) 

user=> (doto-map #{:hello :foo} (fn [k] (.toUpperCase k)) {:hello "World" :try "This" :foo "bar"}) 
{:hello "WORLD", :try "This", :foo "BAR"} 

यह करने के लिए एक बेहतर तरीका हो सकती है:

(let 
    [my-map {:hello "World" :try "This" :foo "bar"}] 
    (println (doToMap my-map [:hello :foo] (fn [k] (.toUpperCase k))) 

यह तो जैसे

{:hello "WORLD" :try "This" :foo "BAR"} 

उत्तर

24
(defn do-to-map [amap keyseq f] 
    (reduce #(assoc %1 %2 (f (%1 %2))) amap keyseq))

ब्रेकडाउन:

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

(some-map some-key) 

हम पुराने मूल्यों लेते हैं, और उन पर कुछ समारोह f फोन करके नए मूल्यों के लिए उन्हें बदलना चाहते हैं। तो एक भी कुंजी दी, नया मान होगा:

(f (some-map some-key)) 

हम अपने हैश-नक्शे पर इस कुंजी के साथ इस नए मान संबद्ध करना चाहते हैं, "की जगह" पुराने मूल्य। यह वही है assoc करता है:

(assoc some-map some-key (f (some-map some-key))) 

("बदलें" डराने-उद्धरण में है, क्योंकि हम एक ही हैश नक्शा वस्तु परिवर्तनशील नहीं कर रहे हैं, हम नई, अपरिवर्तनीय, बदल हैश नक्शा लौट रहे हैं हर बार वस्तुओं हम assoc कहते हैं। यह अभी भी तेजी से और Clojure में कुशल है, क्योंकि हैश नक्शे लगातार कर रहे हैं और शेयर संरचना जब आप assoc उन्हें।)

हम अपने नक्शे पर बार-बार assoc नए मूल्यों, एक समय में एक कुंजी की जरूरत है। तो हमें किसी प्रकार के लूपिंग निर्माण की ज़रूरत है। हम जो चाहते हैं वह हमारे मूल हैश-मैप और एक कुंजी के साथ शुरू करना है, और उसके बाद उस कुंजी के मान को "अपडेट करें"। फिर हम उस नए हैश-मैप और अगली कुंजी लेते हैं, और उस अगली कुंजी के मान को "अपडेट" करते हैं। और हम इसे हर कुंजी के लिए दोहराते हैं, एक बार में, और आखिरकार हैश-मैप वापस लौटाते हैं जिसे हमने "संचित" किया है। यह reduce करता है।

  • reduce को पहले तर्क एक समारोह है कि दो तर्क लेता है: एक "संचायक" मूल्य है, जो मूल्य हम "को अपडेट करने में" अधिक से अधिक रखने के है, और एक ही तर्क एक संचय में कुछ जमा करने के लिए प्रयोग किया जाता है।
  • reduce पर दूसरा तर्क प्रारंभिक मान इस fn के पहले तर्क के रूप में पारित किया गया है।
  • reduce पर तीसरा तर्क एक बार में fn के दूसरे तर्क के रूप में पारित होने के लिए तर्कों का संग्रह है।

तो:

(fn [map-so-far some-key] (assoc map-so-far some-key (f (map-so-far some-key)))) 
reduce में

तो यह प्लग:

(reduce (fn [map-so-far some-key] (assoc map-so-far some-key (f (map-so-far some-key)))) 
     amap 
     keyseq) 

(reduce fn-to-update-values-in-our-map 
     initial-value-of-our-map 
     collection-of-keys) 

fn-to-update-values-in-our-map सिर्फ ऊपर से assoc बयान, एक गुमनाम समारोह में लिपटे है में क्लोजर, अज्ञात कार्यों को लिखने के लिए एक शॉर्टेंड है: #(...) एक अज्ञात fn है जिसमें एक ही फॉर्म शामिल है, जिसमें %1 अज्ञात फ़ंक्शन, %2 दूसरे के लिए पहले तर्क के लिए बाध्य है, इसलिए ऊपर से हमारे fn लिखा जा सकता है समतुल्य रूप के रूप में:

#(assoc %1 %2 (f (%1 %2))) 

यह हमें देता है:

(reduce #(assoc %1 %2 (f (%1 %2))) amap keyseq) 
+1

क्या आप क्लोजर के लिए नए विवरण के लिए बयान विवरण देकर एक बयान देना चाहते हैं? –

+1

उम्मीद है कि मदद करता है। –

+0

कि # (...) नोटेशन अद्भुत है। बहुत बढ़िया जवाब! –

1

कुछ के साथ एक नक्शा परिणाम चाहिए निम्नलिखित काम करने के लिए लगता है। शायद किसी को एक अच्छा एक लाइनर के साथ आ सकते हैं :)

4
(defn doto-map [m ks f & args] 
    (reduce #(apply update-in %1 [%2] f args) m ks)) 

उदाहरण कॉल

+०१२३५१६४१०६
user=> (doto-map {:a 1 :b 2 :c 3} [:a :c] + 2) 
{:a 3, :b 2, :c 5} 

उम्मीद करता है कि इससे मदद मिलती है।

संबंधित मुद्दे