2013-05-18 9 views
5

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

(nth [2 4] 0) ;=> 2 
(nth '(2 4) 0) ;=> 2 
(get [2 4] 0) ;=> 2 
(get '(2 4) 0) ;=> nil -- wtf??? 

get वार्ता एक महत्वपूर्ण मानचित्रण के प्रलेखन को हैरान कर दिया है, लेकिन यह वैक्टर या सेट ठीक से काम करता है। nth का दस्तावेज़ीकरण भी get का उल्लेख करता है, जो कि केवल अंतर-मामलों में उनके मतभेदों के बारे में बात करता है।

वास्तविक दुनिया की स्थिति जहां मुझे इस अजीब व्यवहार का सामना करना पड़ा था, यह था कि मैंने एक याम फ़ाइल लोड की थी। इसके परिणामस्वरूप नक्शे और सूचियों की घोंसला वाली संरचना हुई। मैं get-in के साथ एक तत्व का उपयोग करना चाहता था।

(def form (parse-yaml some-yaml-file)) 
(def best-friend (get-in form [:friends 0 :first-name])) 

यह काम नहीं करता, क्योंकि get-inget आंतरिक रूप से उपयोग करता है। तो मेरे पास सैद्धांतिक और व्यावहारिक प्रश्न है:

  • क्या यह व्यवहार get सही और अपेक्षित माना जाता है? यदि हां, तो कृपया बताएं क्यों।
  • मैप्स और सूचियों की ऐसी संरचना में घोंसला वाले तत्व का उपयोग कैसे कर सकता हूं?

उत्तर

14

get का व्यवहार सही और अपेक्षित है। get "कीड" डेटा संरचनाओं पर काम करता है, जिसमें मान कुंजी के लिए मैप किए जाते हैं। इसमें वेक्टर शामिल हैं, जो मानों के सूचकांक को मैप करते हैं, और सेट करते हैं।

सूचियां तत्वों को यादृच्छिक पहुंच प्रदान नहीं करती हैं; वे रैखिक रूप से घूमने के लिए हैं। चूंकि समर्थित पहुंच पैटर्न बहुत अलग हैं, सूचियां और वैक्टर बिल्कुल का उपयोग एक दूसरे के लिए नहीं किया जाना चाहिए और कोर क्लोजर संग्रह लाइब्रेरी इस तरह के उपयोग का समर्थन करने का कोई प्रयास नहीं करती है। (nth एक फ़ंक्शन का एक अजीब उदाहरण है जो कम-प्रदर्शन निरंतर-या-लॉगरिदमिक-टाइम लुकअप और रैखिक ट्रैवर्सल, क्लोजर भूमि में एक अजीब जानवर दोनों करता है)।

वहाँ के पाठ्यक्रम आगे "संशोधन" के साथ क्या करना मतभेद (लगातार डेटा संरचना अर्थ में: संशोधित प्रतियां बनाने) कर रहे हैं इस तरह के तरीके के रूप में, जिसमें conj काम करता है और वैक्टर के लिए assoc की उपलब्धता (पहले से ही एक में उल्लिखित फुटनोट; किसी सूची में किसी तत्व को प्रतिस्थापित करने में उस बिंदु तक पूरे उपसर्ग को पुनर्निर्माण करना शामिल है)।

यदि आप अपने डेटा के साथ वेक्टर-जैसी पहुंच पैटर्न का उपयोग करना चाहते हैं, तो आपको इसे एक वेक्टर में रखना चाहिए। सूची vec के साथ वैक्टर (रैखिक समय में) में परिवर्तित की जा सकती है। यदि आप एक सीरियलाइजेशन प्रारूप से निपट रहे हैं, जहां यह संदिग्ध है कि कुछ डेटा के लिए सूचियों या वैक्टरों को वापस किया जाना चाहिए और आपका पार्सर इसे बताने के लिए एक विकल्प स्वीकार नहीं करता है, तो आपको इसे कुछ पोस्ट-प्रोसेसिंग करना पड़ सकता है (clojure.walk उपयोगी हो सकता है, विशेष रूप से prewalk और postwalk फ़ंक्शंस; यह मानते हैं कि केवल मूल क्लोजर डेटा प्रकार शामिल हैं)।


वास्तव में, अधिक वैक्टर का सच है: वे साहचर्य कर रहे हैं, ताकि आप उन्हें assoc ((assoc [0 1 2] 0 :foo) रिटर्न [:foo 1 2] साथ उपयोग कर सकते हैं, केवल ऊपर सूचकांक करने के लिए जो पहले से ही ing assoc के लिए, (count the-vector) के सूचकांक का समर्थन कर रहे वेक्टर में मौजूद है और अंत में तुरंत)।

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

5
मीकल Marczyk उत्तम जवाब देने के लिए

कोड उदाहरण के पूरक:

(def form 
    {:friends 
    '({:id 1, :first-name "bob"} 
    {:id 2, :first-name "sue"}) 
    :languages 
    '({:id 1, :name "Clojure"})}) 

(-> form :friends (nth 0) :first-name) 
;=> "bob" 

(def form' 
    (clojure.walk/prewalk #(if (list? %) (vec %) %) form)) 

(get-in form' [:friends 0 :first-name]) 
;=> "bob" 
+0

पिरोया संस्करण के लिए +1, मैं इसके बारे में नहीं सोचा –