【问题标题】:In Scala, is there a way to get the currently evaluated items in a Stream?在 Scala 中,有没有办法在 Stream 中获取当前评估的项目?
【发布时间】:2011-02-19 09:25:52
【问题描述】:

在 Scala 中,有没有办法在 Stream 中获取当前评估的项目?例如在流中

val s: Stream[Int] = Stream.cons(1, Stream.cons(2, Stream.cons(3, s.map(_+1))))

该方法应该只返回List(1,2,3)

【问题讨论】:

    标签: scala stream lazy-evaluation


    【解决方案1】:

    在 2.8 中,有一个名为 tailDefined 的受保护方法,当您到达流中尚未评估的点时,该方法将返回 false。

    这并不太有用(除非您想编写自己的 Stream 类),除了 Cons 本身将方法公开。我不确定为什么它在 Stream 中而不是在 Cons 中受到保护——我认为其中一个可能是一个错误。但是现在,至少,您可以编写这样的方法(编写等效的函数留给读者作为练习):

    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
    

    【讨论】:

    • 方法tailDefinedConsEmpty 中都是公开的,所以我不认为这是一个错误。我之前没有注意到这一点。我可以调整您的解决方案来解决我的问题。
    【解决方案2】:

    基于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())
    }
    

    【讨论】:

      【解决方案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。通过一些解析,您将能够从字符串中获取元素。这是一个几乎不能接受的解决方案,只有整数,我无法想象任何使用字符串解析想法的通用解决方案。

      【讨论】:

        【解决方案4】:

        使用左扫描

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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2020-11-18
          • 2014-08-07
          • 2013-12-23
          • 2012-11-02
          • 1970-01-01
          • 2011-06-19
          相关资源
          最近更新 更多