在Scala中的过滤器,map,flatMap中,如何轻松地从一个集合类型转换为另一个集合类型?

假设我有一个List [Int],并且我想对每个元素调用toString,并返回结果作为Vector [String]。

在Scala中执行此操作的各种方法是什么?有一个解决方案与最少量的显式打字? – 即,我想指定我想要一个向量而不是一个列表,但我想要的String参数从过滤器函数推断。

或者我应该明确地传递一个CanBuildFrom实例?我从哪里得到这些 – 对于Seqs,集和地图?

最佳答案
使用breakOut

使用breakOut作为CanBuildFrom,让让typer知道你想要的结果类型是什么(不幸的是,你需要在这里指定String)

scala> import collection.breakOut
import collection.breakOut

scala> List(1, 2, 3)
res0: List[Int] = List(1, 2, 3)

scala> res0.map(_.toString)(breakOut) : Vector[String]
res2: Vector[String] = Vector(1, 2, 3)

使用到[集合](从Scala 2.10.0开始)

Scala 2.10.0介绍了一种将集合转换为另一个集合的简单方法:

scala> List(1, 2, 3).map(_.toString).to[Vector]
res0: Vector[String] = Vector(1, 2, 3)

使用toIndexedSeq

或者明确要求IndexedSeq:

scala> res0.map(_.toString).toIndexedSeq
res4: scala.collection.immutable.IndexedSeq[String] = Vector(1, 2, 3)

如果要在不创建中间列表的情况下执行此操作,则:

scala> res0.view.map(_.toString).toIndexedSeq
res5: scala.collection.immutable.IndexedSeq[String] = Vector(1, 2, 3)

使用自然变换

你可以做(​​笨拙,但更一般地)使用自然变换

scala> trait Trans[F[_], G[_]] {
 | def f2g[A](f : F[A]) : G[A]
 | }
defined trait Trans

现在提供一个typeclass实例从List〜>矢量变换:

scala> implicit val List2Vector = new Trans[List, collection.immutable.Vector] {
 | def f2g[A](l : List[A]) : Vector[A] = l.map(identity[A])(collection.breakOut)
 | }
List2Vector: java.lang.Object with Trans[List,scala.collection.immutable.Vector] = $anon$1@56329755

定义包装器和隐式转换:

scala> class Clever[M[_], A](ma : M[A]) { def to[N[_]](implicit t : Trans[M, N]) : N[A] = t.f2g(ma) }
defined class Clever

scala> implicit def ma2clever[M[_], A](ma : M[A]) = new Clever[M, A](ma)
ma2clever: [M[_],A](ma: M[A])Clever[M,A]

然后:

scala> List(1, 2, 3).map(_.toString).to[Vector]
res4: Vector[java.lang.String] = Vector(1, 2, 3)

转载注明原文:在Scala中的过滤器,map,flatMap中,如何轻松地从一个集合类型转换为另一个集合类型? - 代码日志