Scala流过滤器行为

时间:2016-08-01 19:01:53

标签: scala stream

我正在玩scala流。 这是从给定数字开始的所有整数流。
我添加了一个println来跟踪函数的每个调用。

def from(n: Int): Stream[Int] = n #:: from({ println(n); n + 1 })

val nats = from(0)         //> nats  : Stream[Int] =  Stream(0, ?)

nats.take(4).toList        //> 0
                           //| 1
                           //| 2
                           //| 3
                           //| res0: List[Int] = List(0, 1, 2, 3, 4)

正如预期的那样,这是我的scala工作表的输出。然后我创建了所有素数的流。

def sieve(s: Stream[Int]): Stream[Int] = {
  s.head #:: sieve(s.tail.filter({ println( "---" ); _ % s.head != 0 }))
}                          //> sieve: (s: Stream[Int])Stream[Int]

val primes = sieve(from(2))//> primes  : Stream[Int] = Stream(2, ?)

primes.take(4).toList      //> 2
                           //| ---
                           //| 3
                           //| 4
                           //| ---
                           //| 5
                           //| 6
                           //| ---
                           //| res1: List[Int] = List(2, 3, 5, 7)

问题就出现了。我认为应该稍微改变一下,添加x参数而不是_占位符。令人惊讶的是,输出结果完全不同:

def sieve(s: Stream[Int]): Stream[Int] = {
  s.head #:: sieve(s.tail.filter(x => { println("---"); (x % s.head) != 0 }))
}                          //> sieve: (s: Stream[Int])Stream[Int]

val primes = sieve(from(2))//> primes  : Stream[Int] = Stream(2, ?)

primes.take(4).toList      //> 2
                           //| ---
                           //| 3
                           //| ---
                           //| 4
                           //| ---
                           //| ---
                           //| 5
                           //| ---
                           //| 6
                           //| ---
                           //| ---
                           //| ---
                           //| res1: List[Int] = List(2, 3, 5, 7)

我不明白为什么所有这些重复。 使用显式参数有什么不对?

2 个答案:

答案 0 :(得分:3)

区别在于{ println( "---" ); _ % s.head != 0 }{ println( "---" ); x => x % s.head != 0 }的缩写,而不是{ x => println( "---" ); x % s.head != 0 }

在第一种情况下,您首先拨打println,然后返回该功能,因此---filter次打印一次{};}在第二个中,每次filter调用被过滤的流的每个元素一次(并且因为sieve是递归的并且再次过滤流,所以对于每个元素,最终会得到多个---输出)。

答案 1 :(得分:0)

让我们在两种情况下比较论证和筛子,仔细看看:

s.tail.filter(     { println( "---" );       _ % s.head  != 0  })
s.tail.filter(x => { println( "--- " + x ); (x % s.head) != 0 })

你看到println电话的区别吗?

现在输出

First:         Second:
//> 2          //> 2
//| ---        //| --- 3

关键区别:

println( "---"      )
println( "--- " + x )

在第二种情况下,您会在破折号后面附加" "+x,这就是案件之间的确切差异。