如何在 Scala 中的过滤器、映射、平面映射期间轻松地从一种集合类型转换为另一种集合类型?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/5593131/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-22 02:56:44  来源:igfitidea点击:

How do I easily convert from one collection type to another during a filter, map, flatMap in Scala?

scalacollectionsmapfilterimplicit-conversion

提问by Jean-Philippe Pellet

Suppose I have a List[Int], and I want to call toStringon each element, and get back the result as a Vector[String].

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

What are the various ways to do this in Scala? Is there a solution with a minimal amount of explicit typing? — i.e., I want to specify that I want a Vectorrather than a List, but I'd like the Stringargument to be inferred from the filter function.

在 Scala 中执行此操作的各种方法是什么?是否有最少显式类型的解决方案?— 即,我想指定我想要 aVector而不是 a List,但我希望String从过滤器函数中推断出参数。

Or should I explicitly pass a CanBuildFrominstance? Where do I get these from — for Seqs, Sets and Maps?

或者我应该明确地传递一个CanBuildFrom实例?我从哪里得到这些——对于Seqs、Sets 和Maps?

回答by oxbow_lakes

Using breakOut

使用突破

Use breakOutas the CanBuildFromand let the typer know what you want your result type to be (unfortunately you need to specify String here)

使用breakOutasCanBuildFrom并让打字机知道您希望结果类型是什么(不幸的是,您需要在此处指定 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)


Using to[Collection] (starting with Scala 2.10.0)

使用 to[Collection](从 Scala 2.10.0 开始)

Scala 2.10.0 introduced an easy way to convert a collection to another collection:

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

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


Using toIndexedSeq

使用 toIndexedSeq

Alternatively ask for an IndexedSeqexplicitly:

或者IndexedSeq明确要求:

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

If you want to do this without creating the intermediate List, then:

如果您想在不创建中间件的情况下执行此操作List,则:

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


Using Natural Transformations

使用自然变换

You could do it (awkwardly, but more generally) using natural transformations

你可以使用自然变换来做到(尴尬,但更普遍)

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

Now provide a typeclass instance from the List ~> Vector transformation:

现在从 List ~> Vector 转换中提供一个类型类实例:

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@56329755

Define a wrapper and an implicit conversion:

定义一个包装器和一个隐式转换:

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]

Then:

然后:

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