Stream

package stream

import Stream._
sealed trait Stream[+A] {

  def toList0: List[A] = this match {
    case Empty      => Nil
    case Cons(h, t) => h() :: t().toList0
  }

  def toList: List[A] = {
    @annotation.tailrec
    def loop(s: Stream[A], acc: List[A]): List[A] = s match {
      case Cons(h, t) => loop(t(), h() :: acc)
      case _          => acc
    }
    loop(this, Nil).reverse
  }

  def take(n: Int): Stream[A] = this match {
    case Cons(h, t) if n > 1  => cons(h(), t().take(n - 1))
    case Cons(h, _) if n == 1 => cons(h(), empty)
    case _                    => empty
  }

  @annotation.tailrec
  final def drop(n: Int): Stream[A] = this match {
    case Cons(_, t) if n > 0 => t().drop(n - 1)
    case _                   => this
  }

  def takeWhile(p: A => Boolean): Stream[A] = this match {
    case Cons(h, t) if (p(h())) => cons(h(), t().takeWhile(p))
    case _                      => empty
  }

  def foldRight[B](z: => B)(f: (A, => B) => B): B =
    this match {
      case Cons(h, t) => f(h(), t().foldRight(z)(f))
      case _          => z
    }

  def exists(p: A => Boolean): Boolean = foldRight(false)((a, b) => p(a) || b)

  def forAll(p: A => Boolean): Boolean = foldRight(true)((a, b) => p(a) && b)

  def takeWhileByFoldRight(p: A => Boolean): Stream[A] = foldRight(empty[A])((a, b) => if (p(a)) cons(a, b) else b)

  def headOption: Option[A] = foldRight(None: Option[A])((a, b) => Some(a))

  def map[B](f: A => B): Stream[B] = foldRight(empty[B])((a, b) => cons(f(a), b))

  def filter(f: A => Boolean): Stream[A] = foldRight(empty[A])((a, b) => if (f(a)) cons(a, b) else b)

  def append[B >: A](s: => Stream[B]): Stream[B] = foldRight(s)((a, b) => cons(a, b))

  def flatMap[B](f: A => Stream[B]): Stream[B] = foldRight(empty[B])((a, b) => f(a).append(b))

  def mapByUnfold[B](f: A => B): Stream[B] = unfold(this) {
    case Cons(h, t) => Some(f(h()), t())
    case _          => None
  }

  def takeByUnfold(n: Int): Stream[A] = unfold((n, this)) {
    case (i, Cons(h, t)) if i > 0 => Some((h(), (i - 1, t())))
    case _                        => None
  }

  def takeWhileByUnfold(f: A => Boolean): Stream[A] = unfold(this) {
    case Cons(h, t) if (f(h())) => Some((h(), t()))
    case _                      => None
  }

  def zipWith[B, C](s: Stream[B])(f: (A, B) => C): Stream[C] = unfold(this, s) {
    case (Cons(h1, t1), Cons(h2, t2)) => Some((f(h1(), h2()), (t1(), t2())))
    case _                            => None
  }

  def zipAll[B](s: Stream[B]): Stream[(Option[A], Option[B])] = unfold(this, s) {
    case (Empty, Empty)               => None
    case (Empty, Cons(h2, t2))        => Some((None, Some(h2())), (empty, t2()))
    case (Cons(h1, t1), Empty)        => Some((Some(h1()), None), (t1(), empty))
    case (Cons(h1, t1), Cons(h2, t2)) => Some((Some(h1()), Some(h2())), (t1(), t2()))
  }

  def tails: Stream[Stream[A]] =
    unfold(this) {
      case Empty => None
      case s     => Some((s, s drop 1))
    } append Stream(empty)

  def startsWith[A](s: Stream[A]): Boolean =
    zipAll(s).takeWhile(!_._2.isEmpty) forAll {
      case (h, h2) => h == h2
    }

  def hasSubsequence[A](s: Stream[A]): Boolean = tails exists (_ startsWith s)

  def scanRight[B](z: B)(f: (A, => B) => B): Stream[B] =
    foldRight((z, Stream(z)))((a, p0) => {
      lazy val p1 = p0
      val b2 = f(a, p1._1)
      (b2, cons(b2, p1._2))
    })._2
}

case object Empty extends Stream[Nothing]
case class Cons[+A](h: () => A, t: () => Stream[A]) extends Stream[A]

object Stream {

  def cons[A](hd: => A, tl: => Stream[A]): Stream[A] = {
    lazy val head = hd
    lazy val tail = tl
    Cons(() => head, () => tail)
  }

  def empty[A]: Stream[A] = Empty

  def apply[A](as: A*): Stream[A] = if (as.isEmpty) empty else cons(as.head, apply(as.tail: _*))

  def constant[A](a: A): Stream[A] = Stream.cons(a, constant(a))

  def from(n: Int): Stream[Int] = Stream.cons(n, from(n + 1))

  def fibs(n: Int, n1: Int): Stream[Int] = Stream.cons(n, fibs(n1, n + n1))

  def unfold[A, S](z: S)(f: S => Option[(A, S)]): Stream[A] = f(z) match {
    case Some((a, s)) => cons(a, unfold(s)(f))
    case _            => empty
  }

  def fromByUnfold(n: Int): Stream[Int] = unfold(n)(n => Some(n, n + 1))

  def constantByUnfold[A](a: A): Stream[A] = unfold(a)(a => Some(a, a))

  def onesByUnfold: Stream[Int] = unfold(1)(_ => Some(1, 1))
}

object Run {

  def main(args: Array[String]): Unit = {

    val s = Stream(1, 2, 3, 4, 5, 6, 7, 8, 9)

    println(s.toList0)
    println(s.toList)

    println(s.take(3))
    println(s.take(3).toList)

    println(s.drop(3))
    println(s.drop(3).toList)

    println(s.takeWhile(x => x < 5))
    println(s.takeWhile(x => x < 5).toList)

    println(s.forAll(_ % 1 == 0))
    println(s.forAll(_ % 2 == 0))

    println(s.takeWhileByFoldRight(_ % 2 == 0))
    println(s.takeWhileByFoldRight(_ % 2 == 0).toList)

    println(s.headOption)
    println(Stream().headOption)

    println(s.map(_ + 1))
    println(s.map(_ + 1).toList)

    println(s.filter(_ % 2 == 0))
    println(s.filter(_ % 2 == 0).toList)

    println(s.append(Stream(11, 12, 13, 14)))
    println(s.append(Stream(11, 12, 13, 14)).toList)

    println(s.flatMap(x => Stream(x + 100)))
    println(s.flatMap(x => Stream(x + 100)).toList)

    println(Stream.constant(12).take(10))
    println(Stream.constant(12).take(10).toList)

    println(Stream.from(12).take(10))
    println(Stream.from(12).take(10).toList)

    println(Stream.fibs(0, 1).take(10))
    println(Stream.fibs(0, 1).take(10).toList)

    println(Stream.unfold(0)(z => Some((z, z + 1))).take(10))
    println(Stream.unfold(0)(z => Some((z, z + 1))).take(10).toList)

    println(Stream.fromByUnfold(12).take(10))
    println(Stream.fromByUnfold(12).take(10).toList)

    println(Stream.constantByUnfold(12).take(10))
    println(Stream.constantByUnfold(12).take(10).toList)

    println(Stream.onesByUnfold.take(10))
    println(Stream.onesByUnfold.take(10).toList)

    println(s.mapByUnfold(_ + 1))
    println(s.mapByUnfold(_ + 1).toList)

    println(s.takeByUnfold(3))
    println(s.takeByUnfold(3).toList)

    println(s.takeWhileByUnfold(x => x < 5))
    println(s.takeWhileByUnfold(x => x < 5).toList)

    println(s.zipWith(Stream(11, 12, 13, 14, 15))(_ + _))
    println(s.zipWith(Stream(11, 12, 13, 14, 15))(_ + _).toList)

    println(s.zipAll(Stream(11, 12, 13, 14, 15)))
    println(s.zipAll(Stream(11, 12, 13, 14, 15)).toList)

    println(s.tails)
    println(s.tails.toList.map(_.toList))

    println(s.startsWith(Stream(1, 2, 3, 4, 5)))
    println(s.startsWith(Stream(1, 12, 3, 4, 5)))

    println(s.hasSubsequence(Stream(3, 4, 5)))
    println(s.hasSubsequence(Stream(3, 44, 5)))

    println(Stream(1, 2, 3).scanRight(0)(_ + _))
    println(Stream(1, 2, 3).scanRight(0)(_ + _).toList)
  }

}
List(1, 2, 3, 4, 5, 6, 7, 8, 9)
List(1, 2, 3, 4, 5, 6, 7, 8, 9)
Cons(<function0>,<function0>)
List(1, 2, 3)
Cons(<function0>,<function0>)
List(4, 5, 6, 7, 8, 9)
Cons(<function0>,<function0>)
List(1, 2, 3, 4)
true
false
Cons(<function0>,<function0>)
List(2, 4, 6, 8)
Some(1)
None
Cons(<function0>,<function0>)
List(2, 3, 4, 5, 6, 7, 8, 9, 10)
Cons(<function0>,<function0>)
List(2, 4, 6, 8)
Cons(<function0>,<function0>)
List(1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 12, 13, 14)
Cons(<function0>,<function0>)
List(101, 102, 103, 104, 105, 106, 107, 108, 109)
Cons(<function0>,<function0>)
List(12, 12, 12, 12, 12, 12, 12, 12, 12, 12)
Cons(<function0>,<function0>)
List(12, 13, 14, 15, 16, 17, 18, 19, 20, 21)
Cons(<function0>,<function0>)
List(0, 1, 1, 2, 3, 5, 8, 13, 21, 34)
Cons(<function0>,<function0>)
List(0, 1, 2, 3, 4, 5, 6, 7, 8, 9)
Cons(<function0>,<function0>)
List(12, 13, 14, 15, 16, 17, 18, 19, 20, 21)
Cons(<function0>,<function0>)
List(12, 12, 12, 12, 12, 12, 12, 12, 12, 12)
Cons(<function0>,<function0>)
List(1, 1, 1, 1, 1, 1, 1, 1, 1, 1)
Cons(<function0>,<function0>)
List(2, 3, 4, 5, 6, 7, 8, 9, 10)
Cons(<function0>,<function0>)
List(1, 2, 3)
Cons(<function0>,<function0>)
List(1, 2, 3, 4)
Cons(<function0>,<function0>)
List(12, 14, 16, 18, 20)
Cons(<function0>,<function0>)
List((Some(1),Some(11)), (Some(2),Some(12)), (Some(3),Some(13)), (Some(4),Some(14)), (Some(5),Some(15)), (Some(6),None), (Some(7),None), (Some(8),None), (Some(9),None))
Cons(<function0>,<function0>)
List(List(1, 2, 3, 4, 5, 6, 7, 8, 9), List(2, 3, 4, 5, 6, 7, 8, 9), List(3, 4, 5, 6, 7, 8, 9), List(4, 5, 6, 7, 8, 9), List(5, 6, 7, 8, 9), List(6, 7, 8, 9), List(7, 8, 9), List(8, 9), List(9), List())
true
false
true
false
Cons(<function0>,<function0>)
List(6, 5, 3, 0)

 

posted on 2016-04-30 08:30  JonkeyGuan  阅读(125)  评论(0编辑  收藏  举报