编译器是否优化了链式映射?
Are chained maps optimized by compiler?
Scala 使用 map
构造将集合转换为另一个集合的惊人方法。
val l = List(1, 2, 3, 4)
l.map(_*_)
将return列表中元素的平方l
我遇到过多个地图链接在一起的各种实例,
val l = List(1, 2, 3, 4)
val res = l.map(_ * _).map(_ + 1).filter(_ < 3)
我认为下面发生的事情等同于下面的事情。
val l = List(1, 2, 3, 4)
val l1 = l.map(_*_)
val l2 = l1.map(_ + 1)
val res = l2.filter(_ < 3)
如果集合太大,创建 l1
和 l2
可能会导致内存问题。
为了解决这个问题,Scala 编译器有什么优化吗?
val l = List(1, 2, 3, 4)
val res = l1.map( _*_ + 1).filter(_ < 3)
通常如果 f
、g
、h
是函数
val l = List(/*something*/)
val res = l.map(f(_)).map(g(_)).map(h(_))
可以转换成
val res = l.map(f _ andThen g _ andThen h _)
Scala 提供 Stream
,这是一个惰性有序集合。
val s = Stream(1, 2, 3, 4)
// note i've changed your sequence of transformations
// a bit, so that it compiles and yields more than one result
val res = s.map(i => i * i).map(_ + 1).filter(_ < 11)
res
现在是 Stream
。尚未执行实际评估,未使用与 s
大小相关的内存块。
如果您打算一次使用 res
中的一个元素,则无需再做任何工作。例如,您可以在 for 语句或理解中直接使用 res
。
for ( elem <- res ) println( s"A value is ${elem}" )
如果您希望 res
作为 List
,您可以在转换序列的末尾调用 .toList
。而不是上面的,使用
val res = s.map(i => i * i).map(_ + 1).filter(_ < 11).toList
s
在创建新的List
时只会遍历一次。
不,因为这需要编译器了解 map
的语义并对待实现它的标准库 classes(因为没有人阻止你写一个 class 这不成立)。有一个 research proposal 最终可能会实现这个...最终。
还有Scala-Blitz which optimizes some collection operations, but fusion and deforestation are listed as future work in this presentation,我认为它们还没有实现。
正如 Steve Waldman 的回答所说,使用 Stream
(或者,更好的是 Iterator
)可以提供帮助,但它不会完全消除中间集合。
Scala 使用 map
构造将集合转换为另一个集合的惊人方法。
val l = List(1, 2, 3, 4)
l.map(_*_)
将return列表中元素的平方l
我遇到过多个地图链接在一起的各种实例,
val l = List(1, 2, 3, 4)
val res = l.map(_ * _).map(_ + 1).filter(_ < 3)
我认为下面发生的事情等同于下面的事情。
val l = List(1, 2, 3, 4)
val l1 = l.map(_*_)
val l2 = l1.map(_ + 1)
val res = l2.filter(_ < 3)
如果集合太大,创建 l1
和 l2
可能会导致内存问题。
为了解决这个问题,Scala 编译器有什么优化吗?
val l = List(1, 2, 3, 4)
val res = l1.map( _*_ + 1).filter(_ < 3)
通常如果 f
、g
、h
是函数
val l = List(/*something*/)
val res = l.map(f(_)).map(g(_)).map(h(_))
可以转换成
val res = l.map(f _ andThen g _ andThen h _)
Scala 提供 Stream
,这是一个惰性有序集合。
val s = Stream(1, 2, 3, 4)
// note i've changed your sequence of transformations
// a bit, so that it compiles and yields more than one result
val res = s.map(i => i * i).map(_ + 1).filter(_ < 11)
res
现在是 Stream
。尚未执行实际评估,未使用与 s
大小相关的内存块。
如果您打算一次使用 res
中的一个元素,则无需再做任何工作。例如,您可以在 for 语句或理解中直接使用 res
。
for ( elem <- res ) println( s"A value is ${elem}" )
如果您希望 res
作为 List
,您可以在转换序列的末尾调用 .toList
。而不是上面的,使用
val res = s.map(i => i * i).map(_ + 1).filter(_ < 11).toList
s
在创建新的List
时只会遍历一次。
不,因为这需要编译器了解 map
的语义并对待实现它的标准库 classes(因为没有人阻止你写一个 class 这不成立)。有一个 research proposal 最终可能会实现这个...最终。
还有Scala-Blitz which optimizes some collection operations, but fusion and deforestation are listed as future work in this presentation,我认为它们还没有实现。
正如 Steve Waldman 的回答所说,使用 Stream
(或者,更好的是 Iterator
)可以提供帮助,但它不会完全消除中间集合。