2011-06-08 14 views
6

मेरे पास एक ऐसा फ़ंक्शन है जो एक नक्शा लौटाता है। चाबियाँ स्थिर हैं, लेकिन मान सशर्त हैं। इस तरह:मैं निश्चित कुंजी और सशर्त मूल्यों के साथ क्लोजर मानचित्र कैसे वापस कर सकता हूं?

(defn map-returning-function [x y] 
    {:a (if (some-test-fn x) "one value" "other value" 
    :b (if (some-test-fn x) 15   25 
    :c (if (different-test y) :one  :two}) 

वहाँ प्रत्येक मान के लिए if परीक्षण लिखने के लिए जरूरत के बिना इस लक्ष्य को हासिल करने के लिए कुछ और अधिक सुरुचिपूर्ण रास्ता नहीं है? केवल अन्य तरह से मैं के बारे में सोच सकते हैं

(defn another-map-returning-function [x y] 
    (if (some-test-fn x) 
    {:a "one value", :b 15, :c (if (different-test y) :one :two)} 
    {:a "other value" :b 25, :c (if (different-test y) :one :two)})) 

है जो मेरे लिए काफी बेहतर प्रतीत नहीं के बाद से यह सशर्त की प्रत्येक शाखा के लिए कुंजी नाम को दोहराता है और यह different-test पर समारोह कॉल की दोहराता है। और स्वर्ग ने मना किया कि मुझे केवल if की बजाय cond की आवश्यकता है।

+0

आप निश्चित रूप से कुछ चालाक कोड है कि अगर समाप्त .... लेकिन यह सिर्फ तीन या चार वर्णों को लिखने से बचने के लिए वास्तव में लायक एक अतिरिक्त अविवेक और/या जटिलता है लिख सकते हैं ?? यह एक ऐसा मामला हो सकता है जहां आपको केआईएसएस सिद्धांत लागू करना चाहिए। – mikera

+0

@ मिकरा: मैं इस मामले में आपके साथ सहमत हूं लेकिन समझता हूं कि मैंने एक प्रश्न के हिस्से के रूप में इसे स्पष्ट करने के लिए थोड़ा सा उदाहरण सरल बनाया है। मैं थोड़ी उम्मीद कर रहा था कि कोई पागल मैक्रो स्किज़ को बाहर निकाल देगा और मुझे दिखाएगा कि यह कैसे हुआ। – stand

उत्तर

4

कैसे इस बारे में:

(let [test-x (some-test x) test-y (some-test y)] 
    (conj 
    (if test-x {:a "one value" :b 15} {:a "other value" :b 25}) 
    (if test-y {:c :one} {:c :two}))) 

स्थितियां एक बार और एक ही स्थान में मार डाला है, तो किसी अन्य रूप में इस्तेमाल किया। यद्यपि संदर्भ और व्यक्तिगत वरीयता पर निर्भर करता है। अधिक अपने उदाहरण की तरह कुछ क्लीनर हो सकता है:

(let [test-x (some-test x) test-y (some-test y)] 
    {:a (if test-x "one value" "other value") 
    :b (if test-x 15 25) 
    :c (if test-y :one :two)}) 
+0

@ स्टैंड, मान लें कि आप इन सशर्त मानचित्रों में से कई को परिभाषित कर रहे हैं, मैं एक मैक्रो लिखने की अनुशंसा करता हूं जो इस उत्तर में बाद वाला कोड उत्पन्न करता है। यह उच्चतम दक्षता और उच्चतम पठनीयता प्रदान करेगा। मैक्रो चौगुनी, एक कुंजी, टेस्ट-एफएन, पैरामीटर, मान सही होने पर एक सूची स्वीकार करेगा, गलत होने पर मूल्य। – bmillare

+0

हाँ, मेरा वर्तमान दृष्टिकोण आपके दूसरे उदाहरण की तरह है। मैंने 'conj' का उपयोग करने के बारे में सोचा नहीं था इसलिए मुझे उस (या संभवतः' विलय ') के साथ प्रयोग करना होगा। मुझे संदेह था कि एक मैक्रो को बुलाया जा सकता है इसलिए मुझे @bmillare concur सुनने में खुशी हुई। एक सामान्यीकृत मैक्रो समाधान के माध्यम से सोच रहा है। – stand

+0

@ स्टैंड यह वास्तव में दायरे पर निर्भर करता है। मैं कल्पना कर सकता हूं कि इससे कुछ मामलों में तर्क प्रोग्रामिंग और एक नियम इंजन भी हो सकता है। :-) मैक्रो इस दिशा में एक कदम है। –

0

आपका पहला कोड उदाहरण मुझे सबसे अधिक पढ़ने योग्य लगता है। पठनीयता अक्सर दक्षता पर बेहतर होती है, जब तक कि आपके कोड का प्रदर्शन महत्वपूर्ण हिस्सा न हो। लेकिन यहां केवल एक बार अपने सशर्तों का मूल्यांकन करने का एक तरीका है। मुझे बहुत संदेह है कि इसका प्रदर्शन आपके कोड के साथ बहुत अंतर करता है। लालित्य के मामले में मैं अभी भी अपना पहला उदाहरण पसंद करता हूं, क्योंकि यह देखने के लिए स्पष्ट है कि कुंजी-मूल्य जोड़े क्या हैं।

(defn another-map-returning-function [x y] 
    (let [first-map (if (some test-fn x) {:a "one value" :b 15} 
             {:a "other value" :b 25})] 
    (assoc first-map :c 
         (if (different-test y) :one :two)))) 
4

एक और भिन्नता एक के बारे में सोच सकता है merge उपयोग करने के लिए है। एक मामला डिफॉल्ट के रूप में कार्य करता है, जिसे फ़ंक्शन तर्कों के आधार पर संशोधित किया जाता है। यदि आवश्यक हो तो इस तरह आप कुछ टिप्पणियों के साथ परीक्षणों और मसालों को आसानी से समूहित कर सकते हैं।

(defn map-returning-function 
    [x y] 
    (merge {:a "other value" 
      :b 25 
      :c :two} 
     (when (some-test-fn x) 
      {:a "one value" 
      :b 15}) 
     (when (different-test y) 
      {:c :one}))) 

वैकल्पिक रूप से आप जो भी डिफ़ॉल्ट मानते हैं उसके आधार पर वैकल्पिक रूप से दूसरी तरफ।

(defn map-returning-function 
    [x y] 
    (merge {:a "one value" 
      :b 15 
      :c :one} 
     (when-not (some-test-fn x) 
      {:a "other value" 
      :b 25}) 
     (when-not (different-test y) 
      {:c :two}))) 
+0

अच्छा! मैंने एक समान दृष्टिकोण के बारे में सोचा था लेकिन इसे लागू करना अच्छा लगा। मुझे लगता है कि प्राकृतिक डिफॉल्ट मानचित्र होने पर यह समझ में आता है। – stand

2

तुम क्या मैं एक तरह से यह करने के लिए कहेंगे पूछ रहे हैं को देखते हुए एक समारोह है कि कुछ इस तरह दिखता निर्माण किया जाएगा:

(pred-map 
    {:a [some-test-fn "one-value" "other-value"] 
    :b [some-test-fn 15 25] 
    :c [different-test :one :two]} 
    x 
    y) 

जहां एक्स के सभी संदर्भों को तर्क है प्रथम, द्वितीय एक

एक तरह से करने के लिए समारोह और y menti0oned प्राप्त करने के लिए इस निम्नलिखित किया जा सकता है:

(defn get-value [p tv fv a] 
    (if (p a) tv fv)) 

(defn get-predicate-set [m] 
    (set (map first (vals m)))) 

(defn get-arg-map [m args] 
    (zipmap (get-predicate-set m) args)) 

(defn get-arg [p m args] 
    ((get-arg-map m args) p)) 

(defn get-key-value-pair-creator [m args] 
    (fn [[k [p tv fv]]] 
    [k 
    (get-value 
     p 
     tv 
     fv 
     (get-arg p m args))])) 


(defn pred-map [m & args] 
    (into {} 
    (map 
     (get-key-value-pair-creator m args) 
     m))) 

हालांकि ये कार्य समानता के कार्यों के लिए मैप किए जा रहे तर्कों पर भरोसा करते हैं (जो संदर्भों के साथ जाना प्रतीत होता है), इसलिए यह दो बराबर अज्ञात कार्यों को एक जैसा नहीं समझा जाएगा।सरल समारोह का पालन करते हुए

(pred-map 
    {:a [(some-test-fn x) "one value" "other-value"] 
    :b [(some-test-fn x) 15 25] 
    :c [(different-test y) :one :two]}) 

:

यदि आप तर्क दोहरा कोई आपत्ति नहीं है तो आप इस तरह लग रही एक सरल समारोह बनाने

(defn pred-map [m] (into {} (for [[k [p tv fv]] m] [k (if p tv fv)]))) 

या pointfree शैली में:

(def pred-map (comp (partial into {}) (partial map (fn [[k [p tv fv]]] [k (if p tv fv)])))) 
1

अभी भी ऐसा करने का एक और तरीका :-)

(defmulti map-returning-function 
    (fn [x y] [ (some-test-fn x) (different-test y) ])) 

(let [x-values {true {:a "one value" :b 15} 
       false {:a "other value" :b 25}} 
     y-values {true {:c :one} false {:c :two}}] 

    (defmethod map-returning-function [false false] [x y] 
    (merge (x-values false) (y-values false))) 

    (defmethod map-returning-function [true true] [x y] 
    (merge (x-values true) (y-values true))) 
...) 
0

बिना किसी अन्य विचारों को चुराकर।

(defn map-returning-function [x y] 
    (let [x-values {true {:a "one value" :b 15} 
        false {:a "other value" :b 25}} 
     y-values {true {:c :one} false {:c :two}} 
     x-key  (some-test-fn x) 
     y-key  (different-test y) ] 
    (merge (x-values x-key) (y-values y-key)))) 
संबंधित मुद्दे

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