2011-12-20 10 views
32

अन्य प्रश्न हैं जैसे Scala: What is the difference between Traversable and Iterable traits in Scala collections? और How would I get the sum of squares of two Lists in Scala? जो आंशिक रूप से प्रश्न का उत्तर देते हैं। मुझे एक सवाल आया कि यह सब एक ही स्थान पर शामिल करता है।स्कैला ट्रैवर्सबल, इटेबल, अनुक्रम, स्ट्रीम और व्यू के सेमेन्टिक्स?

+3

मैं 1 बंद करने के लिए), क्योंकि यह वास्तव में एक विशिष्ट प्रश्न नहीं है, लेकिन सामान्य करने के लिए अब तक मतदान कर रहा हूँ, 2) क्योंकि जानकारी के रूप में स्काला विकसित बासी विकसित करने के लिए की संभावना है और 3) पहले से ही द्वारा अच्छी तरह से परिभाषित क्योंकि सामान्य मामला है [स्काला के स्वयं के प्रलेखन] (http://www.scala-lang.org/docu/files/collections-api/collections.html) है, जो शायद इस तरह के व्यापक जांच (और स्काला के लिए एक बेहतर संसाधन है, कई अन्य भाषाओं के विपरीत, कभी-कभी काफी चुनौतीपूर्ण दस्तावेज होने पर काफी व्यापक है)। – ig0774

+2

@ ig0774 2) मेरी राय में, यह देखने योग्य भविष्य में स्कैला संग्रहों की महत्वपूर्ण अवधारणाओं को महत्वपूर्ण रूप से बदला जा सकता है। अपने तीन अंक –

+7

@ ig0774 इसके विपरीत, मैं नहीं बल्कि वोट से upvoted क्योंकि 1 बंद करने के लिए) मुझे लगता है इस सवाल का आम तौर पर मूल्यवान हैं, और काफी ठोस संक्षेप उत्तर दिया जाना है, 2) क्योंकि वह वर्तमान स्काला संग्रह को समझने के दिल के पास स्थित है पुस्तकालय, और 3) वर्तमान दस्तावेज, हालांकि व्यापक, बहुत फैल गया है; बड़ी तस्वीर प्राप्त करना मुश्किल है। लिंक के लिए –

उत्तर

33

ट्रैवर्सबल संग्रह पदानुक्रम का शीर्ष है। इसकी मुख्य विधि 'foreach' है, इसलिए यह संग्रह के प्रत्येक तत्व के लिए कुछ करने की अनुमति देता है।

एक Iterable एक इटरेटर बना सकता है, जिस पर आधारित foreach लागू किया जा सकता है। यह तत्वों के कुछ क्रम को परिभाषित करता है, हालांकि यह आदेश हर इटरेटर के लिए बदल सकता है।

सेक (यून्स) एक इटरटेबल है जहां तत्वों का क्रम तय किया गया है। इसलिए किसी तत्व की अनुक्रमणिका के बारे में बात करना समझ में आता है।

स्ट्रीम आलसी अनुक्रम हैं। अर्थात। किसी स्ट्रीम के तत्वों का उपयोग किए जाने से पहले गणना नहीं की जा सकती है। यह सभी पूर्णांक के अनुक्रम की तरह अनंत अनुक्रमों के साथ काम करना संभव बनाता है।

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

+9

दृश्य आलसी नहीं, बस गैर सख्त हैं। आलस्य के लिए कैशिंग की आवश्यकता होती है, जो धाराएं करता है, लेकिन विचार नहीं करते हैं। स्पष्टीकरण के लिए –

+0

धन्यवाद। जवाब में इसे ठीक किया। –

+4

@ डैनियलसी। सोब्राल "आलस्य को कैशिंग की आवश्यकता है" - उम, क्या? –

2

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

हालांकि, ऐसा करने पर उत्पन्न होने वाली "समयपूर्व निष्पादन" के साथ एक मुश्किल समस्या है, जिसे इटरेटर का उपयोग करने से बचा जा सकता है लेकिन स्ट्रीम नहीं करता है, और प्रक्रिया में दोनों के बीच एक महत्वपूर्ण अर्थपूर्ण अंतर बताता है। यह शायद सबसे स्पष्ट रूप से इस प्रकार स्पष्ट किया जाता है:

def runiter(start: Int) { 
    // Create a stream that returns successive integers on demand, e.g. 3, 4, 5, .... 
    val iter = { 
    def loop(v: Int): Stream[Int] = { println("I computed a value", v); v} #:: loop(v+1) 
    loop(start) 
    } 
    // Now, sometime later, we retrieve the values .... 
    println("about to loop") 
    for (x <- iter) { 
    if (x < 10) println("saw value", x) else return 
    } 
} 

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

परिणाम:

scala> runiter(3) 
(I computed a value,3) 
about to loop 
(saw value,3) 
(I computed a value,4) 
(saw value,4) 
(I computed a value,5) 
(saw value,5) 
(I computed a value,6) 
(saw value,6) 
(I computed a value,7) 
(saw value,7) 
(I computed a value,8) 
(saw value,8) 
(I computed a value,9) 
(saw value,9) 
(I computed a value,10) 

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

एक साधारण इसे ठीक करने के लिए एक प्रारंभिक खाली धारा का उपयोग कर काम नहीं करता है प्रयास: (पहले की तरह ही)

def runiter(start: Int) { 
    // Create a stream that returns successive integers on demand, e.g. 3, 4, 5, .... 
    val iter = { 
    def loop(v: Int): Stream[Int] = { println("I computed a value", v); v} #:: loop(v+1) 
    Stream[Int]() ++ loop(start) 
    } 
    // Now, sometime later, we retrieve the values .... 
    println("about to loop") 
    for (x <- iter) { 
    if (x < 10) println("saw value", x) else return 
    } 
} 

परिणाम:

scala> runiter(3) 
(I computed a value,3) 
about to loop 
(saw value,3) 
(I computed a value,4) 
(saw value,4) 
(I computed a value,5) 
(saw value,5) 
(I computed a value,6) 
(saw value,6) 
(I computed a value,7) 
(saw value,7) 
(I computed a value,8) 
(saw value,8) 
(I computed a value,9) 
(saw value,9) 
(I computed a value,10) 
हालांकि

, आप इस से ठीक कर सकते हैं एक प्रारंभिक खाली इटरेटर वाले पुनरावर्तक के लिए धारा बदल रहा है, भले ही यह स्पष्ट है जिसका यह मामला है:

def runiter(start: Int) { 
    // Create an iterator that returns successive integers on demand, e.g. 3, 4, 5, .... 
    val iter = { 
    def loop(v: Int): Iterator[Int] = { println("I computed a value", v); Iterator(v)} ++ loop(v+1) 
    Iterator[Int]() ++ loop(start) 
    } 
    // Now, sometime later, we retrieve the values .... 
    println("about to loop") 
    for (x <- iter) { 
    if (x < 10) println("saw value", x) else return 
    } 
} 

परिणाम:

scala> runiter(3) 
about to loop 
(I computed a value,3) 
(saw value,3) 
(I computed a value,4) 
(saw value,4) 
(I computed a value,5) 
(saw value,5) 
(I computed a value,6) 
(saw value,6) 
(I computed a value,7) 
(saw value,7) 
(I computed a value,8) 
(saw value,8) 
(I computed a value,9) 
(saw value,9) 
(I computed a value,10) 

ध्यान दें कि यदि आप प्रारंभिक खाली इटरेटर नहीं जोड़ते हैं, तो आप धाराओं के साथ के रूप में ही समय से पहले निष्पादन समस्या में पड़ जाएगा।

+3

स्ट्रीम संस्करण में आप "वैल इटर" को "def iter" में बदल सकते हैं। यह चाल करेगा। –

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