2011-10-01 15 views
12

Iterator özelliğine göre take yönteminin davranışı hakkında kafam karıştı. Maddeleri tüketmiyor gibi görünüyor. bir scala Iterator öğesinden öğe tüketme

scala> Iterator(1,2,3) 
res0: Iterator[Int] = non-empty iterator 

scala> res0 take 2 toArray 
res1: Array[Int] = Array(1, 2) 

scala> res0.next 
res2: Int = 1 

Görünüşe 2 iki öğe tüketir adım, ancak 3. adımda Iterator ilk öğenin halen: İşte bir örnek. Uygulamaya baktığımda, herhangi bir kopyalama veya arabelleğe alma işlemini göremiyorum, sadece yeni bir Iterator wich delegesi altta yatan birine. Bu nasıl mümkün olabilir? Gerçekten n öğelerini tüketmeyi nasıl yönetebilirim?

cevap

10

Söz konusu yineleyici IndexedSeqLike#Elements (source) içinde tanımlanmıştır. Farklı yineleyici uygulamalarında take'un tutarsız davranışı hakkında bir ticket was recently filed.

Gerçekten N öğelerini tüketmek için, Iterator#next N kere arayın.

Bir tembel (Iterator gibi) olan Stream'u kullanmayı düşünebilirsiniz, ancak aynı zamanda değişmezdir (Iterator'dan farklı olarak).

scala> val s = Stream(1, 2, 3) 
s: scala.collection.immutable.Stream[Int] = Stream(1, ?) 

scala> s.take(2).toList 
res43: List[Int] = List(1, 2) 

scala> s.take(2).toList 
res44: List[Int] = List(1, 2) 

scala> s.drop(2).toList 
res45: List[Int] = List(3) 

scala> {val (s1, s2) = s.splitAt(2); (s1.toList, s2.toList)} 
res46: (List[Int], List[Int]) = (List(1, 2),List(3)) 
+0

Teşekkürler retronym, ben noktayı görüyorum. "Aktarım" ın atılmamı sağlayan şey, "mevcut öğe işaretçisi" gibi bir şeyin olmamasıydı (bu arada, belki Java etkisi nedeniyle, sözde bir şeyden beklenen bir şey olabilir). Şimdi görüyorum ki, bir "drop" dizisi ile "geçerli işaretçiyi" alabiliyorum ve "başa" bakabiliyorum. Tekrar deneyeceğim. – jglatre

1

Öğeleri drop ürününden tüketmek istiyorsunuz. Bir Iterator çağrısında bulunan çoğu yöntemin, daha fazla kullanım için işe yaramazsa, Iterator numarasını kullanacağını unutmayın - davranış tanımlanmamış ve değişebilir.

+0

'drop' aslında 'take' ile aynı tutarsızlığa tabidir. {val i = Yineleyici (1, 2, 3); i.drop (1); i.next} '1' değil,' 2' döndürür. – retronym

+1

@retronym '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' 'yi çağırdığınızda, artık güvenilir bir şekilde kullanılamaz. Bunun yerine, ne 'bırakıldığını 'kullanmalısın. –

+0

İyi nokta. {val i = Yineleyici (1, 2, 3); i.drop (1) .next} 'verir 2. Herşey ama' next() 've' hasNext() '(potansiyel olarak) orijinal yineleyiciyi geçersiz kılar; Bu yöntemler bir * yeni *, geçerli, yineleyici döndürse de. Bunu açıklığa kavuşturmak için belgelendirme katkılarınızı bekliyorum. – retronym

2

Teşekkürler çocuklar.

Bu

bir Iterator öğelerin demet tüketmek benim çözümdür:

implicit def consumable(i: Iterator[_]) = new { 
    def next(n: Int) = { 
     (for (_ <- 1 to n) yield i.next()).iterator 
    } 
    def skip(n: Int) { 
     (1 to n).foreach(_ => i.next()) 
    } 
    } 

herhangi bir yorum kabul edilecektir.

+0

İade türüyle tutarlı olması için tanım şu şekilde olmalıdır: örtülü def sarf malzemesi [T] (i: Yineleyici [T]) aksi halde Yineleyici [Herhangi] – Miquel

İlgili konular