2010-05-02 10 views
31

मेरे पास एक सतत नक्शा है जिसे मैं फ़िल्टर करना चाहता हूं। कुछ इस तरह:क्लोजर में एक सतत मानचित्र को फ़िल्टर कैसे करें?

(filter #(-> % val (= 1)) {:a 1 :b 1 :c 2}) 

ऊपर ([:a 1] [:b 1]) के रूप में बाहर आता है (मानचित्र प्रविष्टियों की एक आलसी अनुक्रम)। हालांकि मैं {:a 1 :b 1} प्राप्त करना चाहता हूं।

मैं मानचित्र को कैसे फ़िल्टर कर सकता हूं ताकि यह मानचित्र प्रविष्टियों के अनुक्रम से इसे पुनर्निर्माण किए बिना मानचित्र बना रहता है?

उत्तर

45

और एक और एक:

(let [m {:a 1 :b 2 :c 1}] 
    (select-keys m (for [[k v] m :when (= v 1)] k))) 
17
(into {} (filter #(-> % val (= 1)) {:a 1 :b 1 :c 2})) 

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

अपडेट किया गया (नीचे टिप्पणी देखें):

नव शुरू की keep समारोह के साथ

, स्रोत जिनमें से आप देख सकते हैं here (Clojure 1.1 में ठीक काम करना चाहिए अगर आप backport करना चाहते हैं), यह एक अच्छा की तरह लगता है जिस तरह से यह के बारे में जाने के लिए अगर आप एक कुंजी रूप nil का उपयोग नहीं करते:

(let [m {:a 1 :b 1 :c 2}] 
    (apply dissoc m (keep #(-> % val (= 1) (if nil (key %))) m))) 
; => {:a 1, :b 1} 

इसके अलावा, अगर आप वास्तव में अपने नक्शे के पुनर्निर्माण से संबंधित एक मंदी देख पा रहे हैं, तो आप के पुनर्निर्माण कदम पर एक क्षणिक मानचित्र का उपयोग कर सकते :

(persistent! (loop [m (transient {}) 
        to-go (seq [[:a 1] [:b 2]])] 
       (if to-go 
       (recur (apply assoc! m (first to-go)) 
         (next to-go)) 
       m))) 
; => {:a 1, :b 2} 
+0

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

+0

ठीक है, मैं देखता हूं कि आपका क्या मतलब है। मैं इसे दूसरे में करने के दो तरीके जोड़ूंगा, लेकिन ध्यान दें कि आपको प्रदर्शन विभाग में एक बड़ा लाभ देखने की संभावना नहीं है (जब तक कि आपके पास वास्तव में एक बड़ा नक्शा न हो और आप केवल एक छोटे से विघटन कर रहे हों चाबियों की संख्या)। –

+0

एचएम, असल में यह "ऐसा करने के दो तरीके" के रूप में नहीं है "इसे करने का एक तरीका और पुनर्निर्माण के बारे में चिंता करने का एक तरीका"। ऐसा नहीं है कि आपको चिंता करने की आवश्यकता है। :-) –

3
मीकल Marczyk को अपनी टिप्पणी प्रति

:

(defn filter* [f map] 
    (reduce (fn [m [k v :as x]] 
      (if-not (f x) 
       (dissoc m k) 
       m)) 
      map map)) 

user> (filter* #(-> % val (= 1)) {:a 1 :b 1 :c 2}) 
{:a 1, :b 1} 

मैं नहीं दिख रहा है कि आप इस बनाम मीकल के संस्करण के साथ ज्यादा हासिल करने के लिए जा रहे हैं।

3

आवश्यकता सभी प्रविष्टियों पार करने के लिए, लेकिन Clojures लगातार नक्शे का लाभ उठाने कर सकते हैं:

(apply dissoc my-map (for [[k v] my-map :when (not= v 1)] k)) 
1

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

(defmacro filter-map [bindings pred m] 
    `(select-keys ~m 
    (for [~bindings ~m 
     :when ~pred] 
     ~(first bindings) 
    ) 
) 
) 

उदाहरण

user=> (filter-map [key val] (even? (:attr val)) {:a {:attr 2} :b {:attr 3} :c {:attr 4}}) 
{:c {:attr 4}, :a {:attr 2}} 
संबंधित मुद्दे