3

有时我需要通过映射另一个具有不同类型的集合来创建一个集合。例如,某些函数需要List[_]作为其参数类型,但我需要通过映射 a 来生成它IndexedSeq[_]

val r = (1 to n).map { ... }
someFunction(r.toList)

虽然我可以通过先调用IndexedSeq[_]'map方法然后再调用 来实现toList这一点,但这会产生一个冗余的中间集合。有什么办法可以在保持代码简洁的同时避免这个多余的步骤?

4

3 回答 3

9

查看完整签名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) 
于 2013-02-18T10:09:46.807 回答
3

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

于 2013-02-18T10:02:47.547 回答
0

使用视图可能会有所帮助?

val r = (1 to n).view.map { … }
someFunction(r.toList)

map函数是一个严格的变压器Range。然而,如果你先把它变成一个视图,那么它Range(这是一个非严格的集合)将被包装在一个map以非严格方式实现的对象中。只有在调用时才会产生完整的值范围toList

于 2013-02-18T09:48:54.147 回答