有时我需要通过映射另一个具有不同类型的集合来创建一个集合。例如,某些函数需要List[_]
作为其参数类型,但我需要通过映射 a 来生成它IndexedSeq[_]
:
val r = (1 to n).map { ... }
someFunction(r.toList)
虽然我可以通过先调用IndexedSeq[_]
'map
方法然后再调用 来实现toList
这一点,但这会产生一个冗余的中间集合。有什么办法可以在保持代码简洁的同时避免这个多余的步骤?
有时我需要通过映射另一个具有不同类型的集合来创建一个集合。例如,某些函数需要List[_]
作为其参数类型,但我需要通过映射 a 来生成它IndexedSeq[_]
:
val r = (1 to n).map { ... }
someFunction(r.toList)
虽然我可以通过先调用IndexedSeq[_]
'map
方法然后再调用 来实现toList
这一点,但这会产生一个冗余的中间集合。有什么办法可以在保持代码简洁的同时避免这个多余的步骤?
查看完整签名map
:
def map[B, That](f: (A) ⇒ B)(implicit bf: CanBuildFrom[List[A], B, That]): That
关键是隐含的CanBuildFrom
,它控制如何从输入集合生成结果集合。CanBuildFrom
我们可以用允许我们构建不同结果集合的显式替换隐式。
更好的是,我们甚至不必编写这个显式方法!它已经存在,以scala.collection.breakOut
. 来自 ScalaDoc:
提供构建特定目标集合 (To') 的 CanBuildFrom 实例,而与原始集合 (From') 无关。
因此,如果我们传入collection.breakOut
,我们可以准确地指定我们想要的map
方法:
val x = IndexedSeq(1,2,3,4,5)
x.map[Int, List[Int]](_ * 2)(collection.breakOut)
> res6: List[Int] = List(2, 4, 6, 8, 10)
collection.breakOut
正如 om-nom-nom 在他的评论中所说,您的问题的答案是。
breakOut
是赋予该map
方法的附加参数,并且 - 为简单起见 - 它允许从以下位置返回不同类型的集合map
:
def directMapExample(seq: Seq[Int]): Set[Int] = seq.map(_ * 2)(collection.breakOut)
请注意,以下内容在编译时失败:
def directMapExample2(seq: Seq[Int]): Set[Int] = seq.map(_ * 2)
有关详细信息,请参阅https://stackoverflow.com/a/1716558/298389。
使用视图可能会有所帮助?
val r = (1 to n).view.map { … }
someFunction(r.toList)
该map
函数是一个严格的变压器Range
。然而,如果你先把它变成一个视图,那么它Range
(这是一个非严格的集合)将被包装在一个map
以非严格方式实现的对象中。只有在调用时才会产生完整的值范围toList
。