web-dev-qa-db-ja.com

Scalaでフィルター、マップ、flatMapを実行中に、あるコレクション型から別のコレクション型に簡単に変換するにはどうすればよいですか?

List[Int]があり、各要素でtoStringを呼び出して、結果をVector[String]として返したいとします。

Scalaでこれを行うためのさまざまな方法は何ですか?最小限の量の明示的な型付けの解決策はありますか? —つまり、VectorではなくListが必要であることを指定したいのですが、String引数をフィルター関数から推測したいのですが。

または、CanBuildFromインスタンスを明示的に渡す必要がありますか? Seqs、SetsおよびMapsの場合、これらはどこから入手できますか?

35

BreakOutの使用

breakOutCanBuildFromとして使用し、タイパーに結果のタイプを指定します(残念ながら、ここで文字列を指定する必要があります)

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)

To [Collection]の使用(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)

中間Listを作成せずにこれを行う場合は、次のようにします。

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

次に、リストから型クラスのインスタンスを提供します〜>ベクトル変換:

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)
54
oxbow_lakes