Scala - 展平包含Seq的Seq

时间:2015-05-21 07:56:54

标签: scala

假设:

Seq(1,2,3) map {
  case 1 => 11
  case 2 => Seq(12,13,14)
  case 3 => 15
}

如何优雅地将其展平为包含Seq[Int]的{​​{1}}?

4 个答案:

答案 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]]
}