2010-12-16 14 views
5

मैं map-longest नामक क्लोजर उपयोगिता फ़ंक्शन लिखने की कोशिश कर रहा हूं (वैकल्पिक नाम सुझाव की सराहना की गई)। इस समारोह निम्नलिखित "हस्ताक्षर" होगा:क्लोजर मानचित्र-सबसे लंबा

(map-longest fun missing-value-seq c1 & colls) 

और map की तरह ही व्यवहार करेंगे, की तुलना में छोड़कर यह समाप्त हो रहा है सबसे लंबे समय तक जब तक आपूर्ति संग्रह संसाधित करना जारी रखेंगे। सबसे लंबे समय से कम संग्रह के लिए, जब यह मानों से बाहर हो जाता है, तो यह उन्हें missing-values-seq से ले जाएगा। यह आलसी होना चाहिए, लेकिन स्पष्ट रूप से अनंत संग्रह के साथ उपयोग नहीं किया जा सकता है।

उदाहरण उपयोग:

(print (apply str 
    (map-longest #(str %1 \space %2 \space %3 \newline) (repeatedly "--") 
    ["a1" "a2" "a3"] ["b1" "b2"] ["c1" "c2" "c3" "c4"]))) 

यह निम्नलिखित उत्पादन का उत्पादन करना चाहिए:

a1 b1 c1 
a2 b2 c2 
a3 -- c3 
-- -- c4 

लेकिन मैं कॉल गलत हो सकता है।

मैं इसे कैसे कार्यान्वित करूं? क्या clojure.core या clojure-contrib लाइब्रेरी में पहले से कुछ ऐसा है? missing-value-seq के विकल्प के रूप में, क्या अनुपलब्ध मान उत्पन्न करने के लिए दूसरे फ़ंक्शन में पास होना बेहतर होगा (उदाहरण: #(identity "--") मेरे उदाहरण में)?

केस का उपयोग करें: मैं क्लोजर/कार्यात्मक प्रोग्रामिंग सीखने में एक अभ्यास के रूप में एक छोटा टेक्स्ट स्पाइडर सॉलिटेयर प्लेयर लिख रहा हूं। मुझे गेम टेबलोज़ (purists के लिए tableaux :-)) प्रदर्शित करने में सक्षम होना चाहिए।

उत्तर

4

यहाँ एक समाधान है:

(defn map-longest 
    ([fn missing-value-fn c1] 
    (map fn c1)) 
    ([fn missing-value-fn c1 & colls] 
    (lazy-seq 
     (when (not-every? empty? (conj colls c1)) 
     (let [firsts (map first (conj colls c1))] 
      (cons 
      (apply fn (map #(if (nil? %) (missing-value-fn) %) firsts)) 
      (apply map-longest 
       (conj (map rest colls) (rest c1) missing-value-fn fn)))))))) 

टेस्ट:

user=> (print (apply str 
     (map-longest #(str %1 \space %2 \space %3 \newline) #(identity "--") 
      ["a1" "a2" "a3"] ["b1" "b2"] ["c1" "c2" "c3" "c4"]))) 
a1 b1 c1 
a2 b2 c2 
a3 -- c3 
-- -- c4 
nil 

ध्यान दें कि मैं missing-value-seq के बजाय missing-value-fn दृष्टिकोण ले लिया है।

अद्यतन

मामले टिप्पणी में ffriend ने उल्लेख की देखभाल करने के कोड अपडेट किया गया।

टेस्ट:

user=> (print (apply str 
      (map-longest #(str %1 \space %2 \space %3 \newline) #(identity "--") 
      ["a1" "a2" nil] ["b1" "b2"] ["c1" "c2" nil "c4"]))) 
a1 b1 c1 
a2 b2 c2 
-- -- -- 
-- -- c4 
nil 

कृपया ध्यान दें कि इस missing-value-fn द्वारा दिए गए मान के साथ colls में nil रों की जगह लेगा।

+0

'(नहीं-हर शून्य बातें पहली बार?)' - यह [ 'c1' c2 शून्य 'सी 3] जैसे दृश्यों के लिए काम नहीं करेगा। – ffriend

+0

@ffriend: क्या आप एक टेस्ट कोड दे सकते हैं? –

+1

इन अनुक्रमों को आजमाएं: ['ए 1' ए 2 शून्य] ['बी 1' बी 2] ['सी 1' सी 2 शून्य 'सी 4]। आप 'पहले' की गणना करने से पहले '(हर? खाली? Cols) 'की जांच करके इसे ठीक कर सकते हैं और' firsts' को गणना करके' पहले स्थान 'को बदलकर' (नक्शा प्रथम-या-वैल (conj colls c1)) (मेरा उत्तर देखें)। – ffriend

1

यह पूरी तरह से नहीं है आप की जरूरत कार्य करते है, लेकिन थोड़ा सरलीकृत संस्करण है, तो आप बिंदु मिल सकता है:

(defn first-or-val [col missing] 
    (if (empty? col) 
    missing 
    (first col))) 

(defn map-longest [f missing-value & cols] 
    (loop [cols cols, ret '()] 
    (cond (every? empty? cols) (reverse ret) 
      :else (recur (map rest cols) 
         (conj ret (apply f (map #(first-or-val % missing-value) 
               cols))))))) 

मैं आलस्य को छोड़ दिया है, और आप delay और force के साथ आसानी से जोड़ सकते हैं। मैंने missing-value-seq को missing-value में भी बदल दिया - मुझे विश्वास है कि अनुक्रम या जनरेटर के साथ इसे बदलने के लिए यह समस्या नहीं है।

उदाहरण:

(print (apply str 
      (map-longest #(str %1 \space %2 \space %3 \newline) "--" 
         ['a1 'a2 'a3] ['b1 'b2] ['c1 'c2 'c3 'c4]))) 

परिणाम:

a1 b1 c1 
a2 b2 c2 
a3 -- c3 
-- -- c4