从Scala集合的设计中我理解如下:
scala> BitSet(1,2,3) map (_ + "a")
res7: scala.collection.immutable.Set[String] = Set(1a, 2a, 3a)
不构建中间数据结构:新的Set是在使用Builder迭代BitSet时构建的。实际上在这种情况下很明显,因为字符串的位组没有意义。
列表中的地图怎么样?我很确定以下内容构建了一个中间列表:
scala> List(1,2,3) map (_ -> "foo") toMap
res8: scala.collection.immutable.Map[Int,java.lang.String] =
Map(1 -> foo, 2 -> foo, 3 -> foo)
即列表List((1,foo), (2,foo), (3,foo))
。如果没有,那怎么样?现在,以下是什么?
scala> Map.empty ++ (List(1,2,3) map (_ -> "foo"))
res10: scala.collection.immutable.Map[Int,java.lang.String] =
Map(1 -> foo, 2 -> foo, 3 -> foo)
这一次,从我似乎从++
的类型中了解到:
def ++ [B >: (A, B), That]
(that: TraversableOnce[B])
(implicit bf: CanBuildFrom[Map[A, B], B, That]): That
我认为可能是地图是动态构建的,并且没有构建中间列表。
是这样的吗?如果是的话,这是确保森林砍伐的规范方法还是有更直接的语法?
答案 0 :(得分:14)
您可以使用breakOut
确保不创建任何中间集合。例如:
// creates intermediate list.
scala> List((3, 4), (9, 11)).map(_.swap).toMap
res542: scala.collection.immutable.Map[Int,Int] = Map(4 -> 3, 11 -> 9)
scala> import collection.breakOut
import collection.breakOut
// doesn't create an intermediate list.
scala> List((3, 4), (9, 11)).map(_.swap)(breakOut) : Map[Int, Int]
res543: Map[Int,Int] = Map(4 -> 3, 11 -> 9)
您可以详细了解here。
<强>更新强>
如果您阅读breakOut
的定义,您会注意到它基本上是一种创建预期类型的CanBuildFrom
对象并将其显式传递给方法的方法。 breakOut
只会使您免于键入以下样板文件。
// Observe the error message. This will tell you the type of argument expected.
scala> List((3, 4), (9, 11)).map(_.swap)('dummy)
<console>:16: error: type mismatch;
found : Symbol
required: scala.collection.generic.CanBuildFrom[List[(Int, Int)],(Int, Int),?]
List((3, 4), (9, 11)).map(_.swap)('dummy)
^
// Let's try passing the implicit with required type.
// (implicitly[T] simply picks up an implicit object of type T from scope.)
scala> List((3, 4), (9, 11)).map(_.swap)(implicitly[CanBuildFrom[List[(Int, Int)], (Int, Int), Map[Int, Int]]])
// Oops! It seems the implicit with required type doesn't exist.
<console>:16: error: Cannot construct a collection of type Map[Int,Int] with elements of type (Int, Int) based on a coll
ection of type List[(Int, Int)].
List((3, 4), (9, 11)).map(_.swap)(implicitly[CanBuildFrom[List[(Int, Int)], (Int, Int), Map[Int, Int]]])
// Let's create an object of the required type ...
scala> object Bob extends CanBuildFrom[List[(Int, Int)], (Int, Int), Map[Int, Int]] {
| def apply(from: List[(Int, Int)]) = foo.apply
| def apply() = foo.apply
| private def foo = implicitly[CanBuildFrom[Nothing, (Int, Int), Map[Int, Int]]]
| }
defined module Bob
// ... and pass it explicitly.
scala> List((3, 4), (9, 11)).map(_.swap)(Bob)
res12: Map[Int,Int] = Map(4 -> 3, 11 -> 9)
// Or let's just have breakOut do all the hard work for us.
scala> List((3, 4), (9, 11)).map(_.swap)(breakOut) : Map[Int, Int]
res13: Map[Int,Int] = Map(4 -> 3, 11 -> 9)
答案 1 :(得分:3)
示例1)正确,没有中间列表
2)是的,你得到一份非常规的清单。
3)再次肯定,你从括号中得到了一份中间名单。没有“神奇”的发生。如果括号中有内容,则首先对其进行评估。
我不确定你在这里的“砍伐森林”是什么意思:根据维基百科,它意味着消除树木结构。如果您的意思是删除中间列表,则应使用视图。例如,请参见:summing a transformation of a list of numbers in scala
因此,如果没有中间结果,您的示例将是
BitSet(1,2,3).view.map(_ + "a").toSet
(toSet
是必需的,否则你有IterableView[String,Iterable[_]]
)
List(1,2,3).view.map(_ -> "foo").toMap
Map.empty ++ (List(1,2,3).view.map(_ -> "foo"))
还有一种用于执行转换操作的force
方法,但这似乎有一个令人讨厌的习惯,就是给你一个更通用的类型(也许某人可以有理由发表评论):
scala> Set(1,2,3).view.map(_ + 1).force
res23: Iterable[Int] = Set(2, 3, 4)