是否有任何方法与map()执行相同的操作但生成不同类型的容器?

时间:2013-02-18 09:36:35

标签: scala scala-collections

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

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

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

3 个答案:

答案 0 :(得分:9)

查看map的完整签名:

def map[B, That](f: (A) ⇒ B)(implicit bf: CanBuildFrom[List[A], B, That]): That

这个的关键是隐式CanBuildFrom,它控制从输入集合生成结果集合的方式。我们可以用一个允许我们构建不同结果集合的显式CanBuildFrom替换隐式scala.collection.breakOut

更好的是,我们甚至不必编写这种显式方法!它已经以collection.breakOut的形式出现了。来自ScalaDoc:

  

提供一个CanBuildFrom实例,用于构建特定目标集合(To'),而不管原始集合(From')。

因此,如果我们传入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) 方法的要求:

{{1}}

答案 1 :(得分:3)

你的问题的答案是collection.breakOut,正如om-nom-nom在他的评论中所述。

breakOutmap方法的附加参数,并且 - 为了简单起见 - 它允许从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

答案 2 :(得分:0)

使用视图可能有帮助吗?

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

map函数是Range上的严格转换。但是,如果首先将其转换为视图,那么Range(这是一个非严格的集合)将被包装在以非严格方式实现map的对象中。只有在调用toList时才会生成全部值。