发生器/块到迭代器/流转换 [英] generator/block to iterator/stream conversion

查看:152
本文介绍了发生器/块到迭代器/流转换的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

基本上我想转换这个:

  def data(block:T => Unit)

到流(dataToStream是一个假设的函数,做这个转换):


$ b b

  val dataStream:Stream [T] = dataToStream(data)


$ b b

我假设这个问题可以通过延续来解决:

  //让我们假设我们不知道数据实现
//我们只知道它产生整数
def data(block:Int => Unit){for(i < - 0 to 10)block(i)}

//这里我们可以打印所有的数据整数
data {i => println(i)}

//>>但是我们真正想要的是将数据转换为流<<

//非常愚蠢的解决方案是将所有数据收集到列表中
var dataList = List [Int]()
data {i = dataList = i :: dataList}
//并从中创建一个流
dataList.toStream

//但是我们想创建一个延迟,CPU和内存高效的流或iterator from data
val dataStream:Stream [Int] = dataToStream(data)
dataStream.foreach {i => println(i)}

//这里有一个黑魔法继续必须使用
//对我来说这个魔法太难理解
//有人知道dataToStream函数可能是什么样子?

谢谢,Dawid

解决方案

EDITED:修改示例以显示traversable.view的延迟。

  scala> def data(f:Int => Unit)= for(i <-1〜10){
| println(Generating+ i)
| f(i)
| }
data:(f:(Int)=>单位)单位

scala> def toTraversable [T](func:(T => Unit)=> Unit)= new Traversable [T] {
| def foreach [X](f:T => X)= func(f(_):Unit) }
toTraversable:[T](func:((T)=> Unit)=> Unit)java.lang.Object with Traversable [T]
pre>

toTraversable方法会将您的数据函数转换为Traversable集合。本身,它没有什么大的,但你可以转换为TraversableView是懒惰。下面是一个例子:

  scala> toTraversable(data).view.take(3).sum 
生成1
生成2
生成3
生成4
res1:Int = 6

take方法的不幸之处在于它必须超过生成的最后一个值才能正常工作,提前终止。上面的代码看起来没有.view调用是一样的。但是,这里有一个更有说服力的例子:

  scala> toTraversable(data).view.take(2).foreach(println)
生成1
1
生成2
2
生成3

总而言之,我相信你正在寻找的集合是TraversableView,这是最容易创建视图制作一个Traversable,然后调用视图就可以了。如果你真的想要Stream类型,这里有一个工作在2.8.0.final的方法,并将创建一个没有线程的Stream:

  scala> def dataToStream(data:(Int => Unit)=> Unit)= {
| val x = new Traversable [Int] {
| def foreach [U](f:Int => U)= {
|数据(f(_):Unit)
| }
| }
| x.view.toList.toStream
| }
dataToStream:(data:((Int)=> Unit)=> Unit)scala.collection.immutable.Stream [Int]

scala> dataToStream(data)
res8:scala.collection.immutable.Stream [Int] = Stream(0,?)


b $ b

这种方法的不幸的性质是,它将在流之前迭代遍历整个遍历。这也意味着所有的值都需要在内存中缓冲。唯一的选择是使用线程。



这是一个动机的理由,喜欢Traversables作为直接返回从scalax.io.File方法:lines chars和bytes。


Basically I want to convert this:

def data(block: T => Unit)

to a Stream (dataToStream is a hypothetical function that do this conversion):

val dataStream: Stream[T] = dataToStream(data)

I suppose this problem could be resolved by continuations:

// let's assume that we don't know how data is implemented
// we just know that it generates integers
def data(block: Int => Unit) { for (i <- 0 to 10) block(i) }

// here we can print all data integers
data { i => println(i) }

// >> but what we really want is to convert data to the stream <<

// very dumb solution is to collect all data into a list
var dataList = List[Int]()
data { i => dataList = i::dataList }
// and make a stream from it
dataList.toStream

// but we want to make a lazy, CPU and memory efficient stream or iterator from data
val dataStream: Stream[Int] = dataToStream(data)
dataStream.foreach { i => println(i) }

// and here a black magic of continuations must be used
// for me this magic is too hard to understand
// Does anybody know how dataToStream function could look like?

Thanks, Dawid

解决方案

EDITED: Modified the examples to show the laziness of traversable.view

scala> def data(f : Int => Unit) = for(i <- 1 to 10) {    
     |   println("Generating " + i)
     |   f(i)
     | }
data: (f: (Int) => Unit)Unit

scala> def toTraversable[T]( func : (T => Unit) => Unit) = new Traversable[T] {
     |   def foreach[X]( f : T => X) = func(f(_) : Unit)                       
     | }                                                                       
toTraversable: [T](func: ((T) => Unit) => Unit)java.lang.Object with Traversable[T]

The toTraversable method will convert your data function into a Traversable collection. By itself, it's nothing huge, but you can convert this to a TraversableView which is lazy. Here's an example:

scala> toTraversable(data).view.take(3).sum
Generating 1
Generating 2
Generating 3
Generating 4
res1: Int = 6

The unfortunate nature of the take method is that it must go one past the last value generated to work correctly, but it will terminate early. The above code would look the same without the ".view" call. However, here's a more compelling example:

scala> toTraversable(data).view.take(2).foreach(println)
Generating 1
1
Generating 2
2
Generating 3

So in conclusion, I believe the collection you're looking for is TraversableView, which is easiest to create view making a Traversable and then calling "view" on it. If you really wanted the Stream type, here's a method that works in 2.8.0.final and will make a "Stream" without threads:

scala> def dataToStream( data : (Int => Unit) => Unit) = {
     |   val x = new Traversable[Int] {                     
     |     def foreach[U](f : Int => U) = {                 
     |        data( f(_) : Unit)                            
     |     }
     |   }
     |   x.view.toList.toStream                             
     | }
dataToStream: (data: ((Int) => Unit) => Unit)scala.collection.immutable.Stream[Int]

scala> dataToStream(data)
res8: scala.collection.immutable.Stream[Int] = Stream(0, ?)

The unfortunate nature of this method is that it will iterate over the entire traversable before making the stream. This also means all the values need to be buffered in memory. The only alternative is to resort to threads.

As an aside: This was the motivating reason to prefer Traversables as direct returns from scalax.io.File methods: "lines" "chars" and "bytes".

这篇关于发生器/块到迭代器/流转换的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆