2010-05-14 27 views

回答

7

2.8中有一个被保护的方法tailDefined,当你到达尚未评估过的流中的点时,它将返回false。

这不是太有用(除非你想写自己的Stream类),但Cons本身使该方法公开。我不确定它为什么在Stream中受到保护,而不在Cons中 - 我认为其中一个可能是一个bug。但现在,至少,你可以写像这样的方法(在刻录功能等同物作为练习留给读者):

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 
    } 
} 

在这里,你可以看到它在行动:

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

'tailDefined'方法在'Cons'和'Empty'中都是公共的,所以我不认为它是一个错误。我以前没注意到。我可以调整你的解决方案来解决我的问题。 – 2010-05-14 20:42:43

3

将该语句键入到交互式shell中,您将看到它的计算结果为s: Stream[Int] = Stream(1, ?)。所以,事实上,2和3的其他两个元素还不知道。

当您访问更多元素时,会计算更多的流。所以,现在将s(3)放入shell中,这将返回res0: Int = 2。现在将s放入shell中,您将看到新值res1: Stream[Int] = Stream(1, 2, 3, 2, ?)

不幸的是,我能找到的唯一一种包含所需信息的方法是s.toString。通过一些解析,您将能够将元素从字符串中取出。这仅仅是一个几乎不可接受的解决方案,我无法想象任何使用字符串解析思想的通用解决方案。

5

基于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

使用scanLeft

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