2013-05-01 11 views
13

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

+0

के संभावित डुप्लिकेट [स्काला में 2 Iterators गठबंधन करने के लिए कैसे?] (Http://stackoverflow.com/questions/9047856/how-to-combine-2-iterators-in -स्काला) –

उत्तर

25

तुम सिर्फ कर सकते हैं:

val it = iter1 ++ iter2 

यह एक और इटरेटर बनाता है और तत्वों का मूल्यांकन नहीं है, लेकिन दो मौजूदा iterators गिर्द घूमती है। यह पूरी तरह से आलसी है, इसलिए आपको ऐसा करने के बाद iter1 या iter2 का उपयोग नहीं करना चाहिए।

val iterators: Seq[Iterator[T]] = ??? 
val it = iterators.foldLeft(Iterator[T]())(_ ++ _) 

आप तत्वों है कि आप जिसके परिणामस्वरूप इटरेटर में बनाए रखने के लिए चाहते हैं पर कुछ आदेश है, लेकिन आप lazyness चाहते हैं,:

सामान्य में, अगर आप मर्ज करना अधिक iterators है, तो आप उपयोग कर सकते हैं तह आप उन्हें धाराओं में परिवर्तित कर सकते हैं:

def merge[T: Ordering](iter1: Iterator[T], iter2: Iterator[T]): Iterator[T] = { 
    val s1 = iter1.toStream 
    val s2 = iter2.toStream 

    def mergeStreams(s1: Stream[T], s2: Stream[T]): Stream[T] = { 
    if (s1.isEmpty) s2 
    else if (s2.isEmpty) s1 
    else if (s1.head < s2.head) s1.head #:: mergeStreams(s1.tail, s2) 
    else s2.head #:: mergeStreams(s1, s2.tail) 
    } 

    mergeStreams(s1, s2).iterator 
} 

हालांकि आवश्यक रूप से तेज़ नहीं है, आपको इसे माइक्रोबेंमार्क करना चाहिए।

एक ही संभावित विकल्प प्राप्त करने के लिए buffered iterators का उपयोग करने का एक संभावित विकल्प है।

+0

ठीक है, मैं कैसे सुनिश्चित कर सकता हूं कि समान सॉर्टिंग मानदंडों के अनुसार सापेक्ष आदेश बनाए रखा जाता है? मान लें कि मेरे पास एक ऑब्जेक्ट है जिसमें 'डेटटाइम' के रूप में टाइमस्टैम्प है। मैं इन दो पुनरावृत्तियों को टाइमस्टैम्प में विलय करने के लिए विलय करना चाहता हूं, एक के बाद नहीं (जावा में मैं तुलनित्र का उपयोग करूंगा) – Bober02

+0

मैंने जवाब संपादित किया। – axel22

+0

धन्यवाद, लेकिन मैं तत्वों को कैश करने के रूप में धाराओं का उपयोग करना चाहता हूं। इसके अलावा, क्या मैं वास्तविक तत्वों पर ऑर्डरिंग प्रदान कर सकता हूं उदा। जावा तुलनाकर्ता की तरह कि आप संग्रह को तर्क के रूप में पास कर सकते हैं? – Bober02

2

आप की कोशिश कर सकते:

(iterA ++ iterB).toStream.sorted.toIterator 

उदाहरण के लिए:

 
val i1 = (1 to 100 by 3).toIterator 
val i2 = (2 to 100 by 3).toIterator 
val i3 = (3 to 100 by 3).toIterator 

val merged = (i1 ++ i2 ++ i3).toStream.sorted.toIterator 

merged.next // results in: 1 
merged.next // results in: 2 
merged.next // results in: 3 
+0

ओह, मेरे बुरे। मुझे लगता है कि आप स्ट्रीम का उपयोग नहीं करना चाहते हैं। –

4

@ axel22 की तरह उल्लेख किया है, आप BufferedIterators के साथ ऐसा कर सकते हैं। यहाँ एक स्ट्रीम से मुक्त समाधान है:

def combine[T](rawIterators: List[Iterator[T]])(implicit cmp: Ordering[T]): Iterator[T] = { 
    new Iterator[T] { 
    private val iterators: List[BufferedIterator[T]] = rawIterators.map(_.buffered) 

    def hasNext: Boolean = iterators.exists(_.hasNext) 

    def next(): T = if (hasNext) { 
     iterators.filter(_.hasNext).map(x => (x.head, x)).minBy(_._1)(cmp)._2.next() 
    } else { 
     throw new UnsupportedOperationException("Cannot call next on an exhausted iterator!") 
    } 
} 
संबंधित मुद्दे