假设:
Seq(1,2,3) map {
case 1 => 11
case 2 => Seq(12,13,14)
case 3 => 15
}
如何优雅地将其展平为包含Seq[Int]
的{{1}}?
答案 0 :(得分:6)
以下是一种方法:
Seq(1,2,3) flatMap {
case 1 => Seq(11)
case 2 => Seq(12,13,14)
case 3 => Seq(15)
}
res0:Seq [Int] = List(11,12,13,14,15)
答案 1 :(得分:1)
这是另一种方法:
implicit def unitSeq[T](x: T): Seq[T] = Seq(x)
Seq(1, 2, 3) flatMap {
case 1 => 11
case 2 => Seq(12, 13, 14)
case 3 => 15
}
res0:Seq [Int] = List(11,12,13,14,15)
答案 2 :(得分:1)
当你Seq(1,2,3)
时,你有一个Seq[Int]
。
在地图操作后,您遇到了问题
val mapped = Seq(1,2,3) map {
case 1 => 11
case 2 => Seq(12,13,14)
case 3 => 15
}
mapped
的类型是什么?对此的合理答案可能是它没有类型。这接近事实。结果类型为Seq[Any]
。不幸的是,这是一种完全没用的类型。这不是你可以用类型安全的方式做任何有用的事情,并且可以说Scala不应该首先允许推断这种类型。
解决方案不是让它在第一时间走得那么远,而是映射到具有合理类型的东西。 Simon展示的解决方案是一种合理的方法:
val mapped = Seq(1,2,3) map {
case 1 => Seq(11)
case 2 => Seq(12,13,14)
case 3 => Seq(15)
case _ => throw new Exception("uh oh, didn't account for this to happen!")
}
现在已映射为Seq[Seq[Int]]
,我们可以使用它做更多有用的事情,例如将其展平为Seq[Int]
mapped.flatten
但我们可以一气呵成。 flatMap
上有一个名为Seq[A]
的操作,它接受一个函数A => Seq[A]
作为参数,并返回一个Seq[A]
。
val flatmapped = Seq(1,2,3) flatMap {
case 1 => Seq(11)
case 2 => Seq(12,13,14)
case 3 => Seq(15)
case _ => throw new Exception("uh oh, didn't account for this to happen!")
}
flatmapped
现在是Seq(11, 12, 13, 14, 15)
除了
顺便说一下,对各种参数化类型进行此操作非常有用:(F[A], A => F[A]) => F[A]
例如:
Option[A].flatMap(a: A => Option[A]): Option[A]
def squareroot(x: Double): Option[Double] = if (x >= 0) Some(Math.sqrt(x))
else None
Some(4.0).flatMap(squareroot) == Some(2.0)
Some(-1.0).flatMap(squareroot) == None
None.flatMap(squareroot) == None
或
Future[A].flatMap(a: A => Future[A]): Future[A]
此操作有时称为flatMap
,有时称为bind
,有时表示为=>>
,如果是支持此操作的类型(称为F[A]
) ,并支持另一个可以从F[A]
创建A
的操作(有时称为point
,有时称为return
),并遵循这些操作如何构成的一些条件,F[A]
形成Monad
答案 3 :(得分:0)
如果您已有此列表,则可以执行flatMap
以获得所需结果:
val list = Seq(11, Seq(12, 13, 14), 15)
val flattened = list.flatMap {
case x: Int => Seq(x)
case y: Seq[Int] => y
}
为避免出现警告(但是,它不能帮助您使此代码类型安全),您可以使用以下内容:
val flattened = list.flatMap {
case x: Int => Seq(x)
case y: Seq[_] => y.asInstanceOf[Seq[Int]]
}