ये दोनों इंटरफेस केवल एक विधि को परिभाषित करते हैं
public operator fun iterator(): Iterator<T>
दस्तावेज़ीकरण का कहना Sequence
है कि आलसी होना है। लेकिन Iterable
आलसी भी नहीं है (जब तक कि एक के द्वारा समर्थित नहीं है Collection
)?
ये दोनों इंटरफेस केवल एक विधि को परिभाषित करते हैं
public operator fun iterator(): Iterator<T>
दस्तावेज़ीकरण का कहना Sequence
है कि आलसी होना है। लेकिन Iterable
आलसी भी नहीं है (जब तक कि एक के द्वारा समर्थित नहीं है Collection
)?
जवाबों:
महत्वपूर्ण अंतर शब्दार्थ में है और stdlib विस्तार कार्यों के कार्यान्वयन के लिए Iterable<T>
और Sequence<T>
।
के लिए Sequence<T>
, विस्तार कार्यों lazily, इसी तरह जावा स्ट्रीम करने के लिए प्रदर्शन जहां संभव मध्यवर्ती आपरेशनों। उदाहरण के लिए, Sequence<T>.map { ... }
किसी अन्य को लौटाता है और Sequence<R>
वास्तव में तब तक आइटम को संसाधित नहीं करता है जब तक कि टर्मिनल ऑपरेशन जैसे toList
या fold
कहा जाता है।
इस कोड पर विचार करें:
val seq = sequenceOf(1, 2)
val seqMapped: Sequence<Int> = seq.map { print("$it "); it * it } // intermediate
print("before sum ")
val sum = seqMapped.sum() // terminal
यह प्रिंट करता है:
before sum 1 2
Sequence<T>
जब आप जितना संभव हो टर्मिनल संचालन में किए गए काम को कम करना चाहते हैं, तो जावा स्ट्रीम्स के लिए आलसी उपयोग और कुशल पाइपलाइनिंग का इरादा है । हालांकि, आलस्य कुछ ओवरहेड का परिचय देता है, जो छोटे संग्रह के सामान्य सरल परिवर्तनों के लिए अवांछनीय है और उन्हें कम प्रदर्शन करता है।
सामान्य तौर पर, यह निर्धारित करने का कोई अच्छा तरीका नहीं है कि इसकी आवश्यकता कब है, इसलिए कोटलिन में स्टडीलिब आलस को स्पष्ट किया जाता है और Sequence<T>
इसे Iterable
डिफ़ॉल्ट रूप से सभी एस पर उपयोग करने से बचने के लिए इंटरफ़ेस में निकाला जाता है।
के लिए Iterable<T>
, इसके विपरीत, के साथ विस्तार कार्यों मध्यवर्ती आपरेशन अर्थ विज्ञान बेसब्री से काम करते हैं, आइटम अभी की प्रक्रिया और एक अन्य लौटने Iterable
। उदाहरण के लिए, इसमें मैपिंग परिणाम के साथ Iterable<T>.map { ... }
देता List<R>
है।
Iterable के लिए समान कोड:
val lst = listOf(1, 2)
val lstMapped: List<Int> = lst.map { print("$it "); it * it }
print("before sum ")
val sum = lstMapped.sum()
यह प्रिंट करता है:
1 2 before sum
जैसा कि ऊपर कहा गया है, Iterable<T>
डिफ़ॉल्ट रूप से गैर-आलसी है, और यह समाधान खुद को अच्छी तरह से दिखाता है: ज्यादातर मामलों में यह संदर्भ की अच्छी स्थानीयता है इस प्रकार सीपीयू कैश, भविष्यवाणी, प्रीफेटिंग आदि का लाभ उठाता है ताकि एक संग्रह की एकाधिक प्रतिलिपि अभी भी अच्छा काम करे। पर्याप्त और छोटे संग्रह के साथ सरल मामलों में बेहतर प्रदर्शन करता है।
यदि आपको मूल्यांकन पाइपलाइन पर अधिक नियंत्रण की आवश्यकता है, तो Iterable<T>.asSequence()
फ़ंक्शन के साथ एक आलसी अनुक्रम का एक स्पष्ट रूपांतरण है ।
map
, filter
और अन्य लोग स्रोत संग्रह प्रकार के अलावा अन्य को तय करने के लिए पर्याप्त जानकारी नहीं रखते हैं, और चूंकि अधिकांश संग्रह Iterable भी हैं, इसलिए यह "आलसी" होने के लिए एक अच्छा मार्कर नहीं है क्योंकि यह है आमतौर पर हर कोई। आलसी को सुरक्षित होने के लिए स्पष्ट होना चाहिए।
हॉटकी का उत्तर पूर्ण करना:
यह देखना महत्वपूर्ण है कि आपके तत्वों में अनुक्रम और Iterable कैसे पुनरावृत्त होते हैं:
अनुक्रम उदाहरण:
list.asSequence().filter { field ->
Log.d("Filter", "filter")
field.value > 0
}.map {
Log.d("Map", "Map")
}.forEach {
Log.d("Each", "Each")
}
लॉग रिजल्ट:
फ़िल्टर - मानचित्र - प्रत्येक; फ़िल्टर - मानचित्र - प्रत्येक
उदाहरण योग्य उदाहरण:
list.filter { field ->
Log.d("Filter", "filter")
field.value > 0
}.map {
Log.d("Map", "Map")
}.forEach {
Log.d("Each", "Each")
}
फ़िल्टर - फ़िल्टर - मानचित्र - मानचित्र - प्रत्येक - प्रत्येक
Iterable
कोjava.lang.Iterable
इंटरफ़ेस पर मैप किया जाता हैJVM
, और सूची या सेट जैसे आमतौर पर उपयोग किए जाने वाले संग्रह द्वारा कार्यान्वित किया जाता है। इन पर संग्रह विस्तार कार्यों का उत्सुकता से मूल्यांकन किया जाता है, जिसका अर्थ है कि वे सभी तुरंत अपने इनपुट में सभी तत्वों को संसाधित करते हैं और परिणाम सहित एक नया संग्रह लौटाते हैं।यहां सूची में पहले पांच लोगों के नाम पाने के लिए संग्रह कार्यों का उपयोग करने का एक सरल उदाहरण है, जिनकी आयु कम से कम 21 है:
val people: List<Person> = getPeople() val allowedEntrance = people .filter { it.age >= 21 } .map { it.name } .take(5)
लक्ष्य प्लेटफ़ॉर्म: JVMRunning पर kotlin v। 1.3.61 सबसे पहले, सूची में हर एक व्यक्ति के लिए उम्र की जाँच की जाती है, जिसके परिणाम एकदम नए सूची में डाले जाते हैं। फिर, उनके नाम की मैपिंग प्रत्येक व्यक्ति के लिए की जाती है, जो फ़िल्टर ऑपरेटर के बाद बने रहे, एक और नई सूची (यह अब है
List<String>
) में समाप्त हो जाएगी । अंत में, पिछली सूची के पहले पांच तत्वों को शामिल करने के लिए बनाई गई एक आखिरी नई सूची है।इसके विपरीत, Sequence मूल्यों के एक आलसी मूल्यांकन वाले संग्रह का प्रतिनिधित्व करने के लिए कोटलिन में एक नई अवधारणा है।
Sequence
इंटरफ़ेस के लिए समान संग्रह एक्सटेंशन उपलब्ध हैं , लेकिन ये तुरंत अनुक्रम उदाहरण लौटाते हैं जो दिनांक की एक संसाधित स्थिति का प्रतिनिधित्व करते हैं, लेकिन वास्तव में किसी भी तत्व को संसाधित किए बिना। प्रसंस्करण शुरू करने के लिए,Sequence
एक टर्मिनल ऑपरेटर के साथ समाप्त किया जाना चाहिए, ये मूल रूप से अनुक्रम के लिए एक अनुरोध है जो उस डेटा का प्रतिनिधित्व करता है जो इसे कुछ ठोस रूप में प्रस्तुत करता है। उदाहरणों में शामिल हैंtoList
,toSet
और, औरsum
केवल कुछ का उल्लेख करने के लिए। जब इन्हें बुलाया जाता है, तो मांग की गई परिणाम का उत्पादन करने के लिए केवल न्यूनतम आवश्यक संख्या में तत्वों को संसाधित किया जाएगा।एक मौजूदा संग्रह को एक अनुक्रम में बदलना बहुत सीधा है, आपको बस
asSequence
एक्सटेंशन का उपयोग करने की आवश्यकता है । जैसा कि ऊपर उल्लेख किया गया है, आपको एक टर्मिनल ऑपरेटर भी जोड़ने की आवश्यकता है, अन्यथा अनुक्रम कभी भी कोई प्रसंस्करण नहीं करेगा (फिर से, आलसी)।
val people: List<Person> = getPeople() val allowedEntrance = people.asSequence() .filter { it.age >= 21 } .map { it.name } .take(5) .toList()
टारगेट प्लेटफ़ॉर्म: JVMRunning on kotlin v। 1.3.61 इस मामले में, Sequence में व्यक्ति के उदाहरण उनकी उम्र के लिए प्रत्येक चेक किए जाते हैं, यदि वे पास होते हैं, तो उनका नाम निकाला जाता है, और फिर परिणाम सूची में जोड़ा जाता है। यह मूल सूची में प्रत्येक व्यक्ति के लिए दोहराया जाता है जब तक कि पांच लोग नहीं मिलते। इस बिंदु पर, टॉलिस्ट फ़ंक्शन एक सूची देता है, और बाकी लोगों को
Sequence
संसाधित नहीं किया जाता है।इसमें कुछ अतिरिक्त भी है जो अनुक्रम में सक्षम है: इसमें कई प्रकार की वस्तुएं हो सकती हैं। इस परिप्रेक्ष्य में, यह समझ में आता है कि ऑपरेटर जिस तरह से काम करते हैं - अनंत अनुक्रम पर एक ऑपरेटर कभी नहीं लौट सकता है अगर यह अपने काम को उत्सुकता से करता है।
एक उदाहरण के रूप में, यहां एक अनुक्रम है जो अपने टर्मिनल ऑपरेटर द्वारा आवश्यक के रूप में 2 की कई शक्तियों को उत्पन्न करेगा (इस तथ्य की अनदेखी करते हुए कि यह जल्दी से प्रवाह होगा):
generateSequence(1) { n -> n * 2 } .take(20) .forEach(::println)
आप यहां अधिक पा सकते हैं ।
Java
(ज्यादातरGuava
) प्रशंसकों के लिए एक बड़ा आश्चर्य