2010-05-14 5 views

Antwort

7

In 2.8 gibt es eine geschützte Methode namens tailDefined, die false zurückgibt, wenn Sie an den Punkt im Stream gelangen, der noch nicht ausgewertet wurde.

Dies ist nicht sehr nützlich (es sei denn, Sie möchten Ihre eigene Stream Klasse schreiben), außer dass Cons selbst die Methode veröffentlicht. Ich bin nicht sicher, warum es in Stream und nicht in Cons geschützt ist - ich würde denken, dass der eine oder der andere ein Bug sein könnte. Aber jetzt, zumindest, können Sie eine Methode, wie so schreiben (ein funktionales Äquivalent Schreiben wird dem Leser als Übung):

def streamEvalLen[T](s: Stream[T]) = { 
    if (s.isEmpty) 0 
    else { 
    var i = 1 
    var t = s 
    while (t match { 
     case c: Stream.Cons[_] => c.tailDefined 
     case _ => false 
    }) { 
     i += 1 
     t = t.tail 
    } 
    i 
    } 
} 

Hier können Sie es in Aktion sehen:

scala> val s = Stream.iterate(0)(_+1) 
s: scala.collection.immutable.Stream[Int] = Stream(0, ?) 

scala> streamEvalLen(s) 
res0: Int = 1 

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

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

scala> streamEvalLen(s) 
res3: Int = 3 
+0

Die Methode 'tailDefined' ist sowohl in' Cons' als auch 'Empty' öffentlich und ich glaube nicht, dass es ein Fehler ist. Das habe ich vorher nicht bemerkt. Ich kann Ihre Lösung anpassen, um mein Problem zu lösen. –

3

Geben Sie diese Anweisung in die interaktive Shell ein, und Sie werden sehen, dass sie s: Stream[Int] = Stream(1, ?) ergibt. In der Tat sind die anderen zwei Elemente von 2 und 3 noch nicht bekannt.

Wenn Sie auf weitere Elemente zugreifen, wird mehr vom Stream berechnet. Also, setzen Sie jetzt s(3) in die Shell, die res0: Int = 2 zurückgibt. Setzen Sie nun s in die Shell und Sie sehen den neuen Wert res1: Stream[Int] = Stream(1, 2, 3, 2, ?).

Die einzige Methode, die ich finden konnte, dass die Informationen enthielt, die Sie wollten, war leider s.toString. Mit etwas Analyse werden Sie in der Lage sein, die Elemente wieder aus der Zeichenfolge zu entfernen. Dies ist eine kaum akzeptable Lösung mit nur wenigen Ints und ich konnte mir keine generische Lösung vorstellen, die die String-Parsing-Idee verwendet.

5

Die Lösung basiert auf Rex's answer:

def evaluatedItems[T](stream: => Stream[T]): List[T] = { 
    @tailrec 
    def inner(s: => Stream[T], acc: List[T]): List[T] = s match { 
    case Empty => acc 
    case c: Cons[T] => if (c.tailDefined) { 
     inner(c.tail, acC++ List(c.head)) 
    } else { acC++ List(c.head) } 
    } 
    inner(stream, List()) 
} 
0

Mit scanLeft

lazy val s: Stream[Int] = 1 #:: s.scanLeft(2) { case (a, _) => 1 + a } 
Verwandte Themen