Как мне легко конвертировать из одного типа коллекции в другой во время фильтра, карты, flatMap в Scala? - PullRequest
34 голосов
/ 08 апреля 2011

Предположим, у меня есть List[Int], и я хочу вызвать toString для каждого элемента и получить результат как Vector[String].

Какие существуют способы сделать это в Scala? Есть ли решение с минимальным количеством явной типизации? Я хочу указать, что я хочу Vector, а не List, но я бы хотел, чтобы аргумент String выводился из функции фильтра.

Или я должен явно передать экземпляр CanBuildFrom? Где я могу получить их из-за Seq с, Set с и Map с?

1 Ответ

53 голосов
/ 08 апреля 2011

Использование breakOut

Используйте breakOut в качестве CanBuildFrom и дайте типеру знать, каким должен быть ваш тип результата (к сожалению, вам нужно указать здесь 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)

Если вы хотите сделать это без создания промежуточного звена 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

Теперь предоставьте экземпляр класса типов из преобразования 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$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)
...