2009-07-25 11 views
10

क्लोजर में द्वि-दिशात्मक मानचित्र को लागू करने का सबसे अच्छा तरीका क्या होगा? (द्वि-दिशात्मक मानचित्र से, मेरा मतलब है एक सहयोगी मानचित्र जो ए-> बी और बी-> ए एक्सेस दोनों प्रदान कर सकता है। असल में, मान खुद विपरीत दिशा में जाने के लिए कुंजी होंगे।)क्लोजर में एक द्वि-दिशात्मक मानचित्र?

I मान लीजिए कि मैं दो दिशाओं को स्थापित कर सकता हूं, प्रत्येक दिशा में एक, लेकिन क्या ऐसा करने का एक और बेवकूफ तरीका है?

मुझे उन मामलों में दिलचस्पी है जहां हम एक विभाजन चाहते हैं, जिसका अर्थ है कि कोई भी दो चाबियाँ उसी मूल्य पर मैप नहीं कर सकती हैं, और ऐसे मामले जहां वह स्थिति लागू नहीं होती है।

उत्तर

12

आप इसके लिए जावा लाइब्रेरी का उपयोग हमेशा कर सकते हैं, जैसे Apache commons में संग्रहों में से एक। TreeBidiMap java.util.Map लागू करता है, इसलिए यह किसी भी प्रयास के बिना भी सक्षम है।

user> (def x (org.apache.commons.collections.bidimap.TreeBidiMap.)) 
#'user/x 
user> (.put x :foo :bar) 
nil 
user> (keys x) 
(:foo) 
user> (.getKey x :bar) 
:foo 
user> (:foo x) 
:bar 
user> (map (fn [[k v]] (str k ", " v)) x) 
(":foo, :bar") 

कुछ बातें हालांकि काम करेंगे नहीं, assoc और dissoc की तरह है, क्योंकि वे लगातार संग्रह उम्मीद और TreeBidiMap परिवर्तनशील है।

यदि आप वास्तव में मूल क्लोजर में ऐसा करना चाहते हैं, तो आप रिवर्स-दिशा हैश को पकड़ने के लिए मेटाडेटा का उपयोग कर सकते हैं। यह अभी भी आपकी मेमोरी आवश्यकताओं को दोगुना करने जा रहा है और प्रत्येक ऐड और डिलीट के लिए समय दोगुना कर देगा, लेकिन लुकअप पर्याप्त तेज़ होगा और कम से कम सबकुछ बंडल हो जाएगा।

(defn make-bidi [] 
    (with-meta {} {})) 

(defn assoc-bidi [h k v] 
    (vary-meta (assoc h k v) 
      assoc v k)) 

(defn dissoc-bidi [h k] 
    (let [v (h k)] 
    (vary-meta (dissoc h k) 
       dissoc v))) 

(defn getkey [h v] 
    ((meta h) v)) 

आपको पाठ्यक्रम की पूर्ण कार्यक्षमता प्राप्त करने के लिए शायद अन्य कार्यों का एक समूह लागू करना होगा। यह सुनिश्चित नहीं है कि यह दृष्टिकोण कितना व्यवहार्य है।

user> (def x (assoc-bidi (make-bidi) :foo :bar)) 
#'user/x 
user> (:foo x) 
:bar 
user> (getkey x :bar) 
:foo 
+1

धन्यवाद, यह सहायक है। मैं क्लोजर देशी विकल्प चुनना पसंद करूंगा, इसलिए आपका दूसरा विचार कुछ ऐसा है जो मैं कोशिश कर सकता हूं। –

3

ज्यादातर मामलों के लिए, मैं निम्नलिखित काम करता मिल गया है ठीक:

(defn- bimap 
    [a-map] 
    (merge a-map (clojure.set/map-invert a-map))) 

यह केवल उल्टे नक्शे के साथ मूल नक्शा एक नया मानचित्र में, मर्ज हो जाएंगे तो आप सामान्य मानचित्र आपरेशन उपयोग कर सकते हैं नतीजे के साथ।

यह तेज़ और गंदा है, लेकिन स्पष्ट रूप से आपको इस कार्यान्वयन से बचना चाहिए यदि किसी भी कुंजी किसी भी मान के समान हो या a-map में मान अद्वितीय नहीं हैं।

1

इस प्रकार हम इस समस्या reframe कर सकते हैं:
tuples ([a1 b1] [a2 b2] ...) की एक सूची हम जल्दी से a और b दोनों से tuples देखने के लिए सक्षम होना चाहते हैं को देखते हुए। तो हम मैपिंग a -> [a b] और b -> [a b] चाहते हैं। जिसका अर्थ है कि कम से कम tuples साझा किया जा सकता है। और यदि हम इसे लागू करने के बारे में सोचते हैं तो यह जल्दी से स्पष्ट हो जाता है कि यह कॉलम ए और बी के साथ एक मेमोरी डेटाबेस तालिका है जो दोनों कॉलम द्वारा अनुक्रमित है।

तो आप केवल हल्के वजन वाले मेमोरी डेटाबेस का उपयोग कर सकते हैं।

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

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