简体   繁体   English

Scala-包含Seq的平坦Seq

[英]Scala - flatten Seq containing Seq

Given: 鉴于:

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

How can I elegantly flatten this to a Seq[Int] containing Seq(11,12,13,14,15) ? 如何优雅地将其展平为包含Seq(11,12,13,14,15)Seq[Int]

Here's one way to do it: 这是一种实现方法:

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) res0:Seq [Int] =列表(11,12,13,13,14,15)

Here's another way to do it: 这是另一种方法:

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) res0:Seq [Int] =列表(11,12,13,13,14,15)

When you have Seq(1,2,3) you have a Seq[Int] . 当您有Seq(1,2,3)您就有一个Seq[Int]

after your map operation you have a problem though 地图操作后,您仍然遇到问题

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

What is the type of mapped ? mapped的类型是什么? A reasonable answer to this could be that it doesn't have a type. 对此的合理答案可能是它没有类型。 That's close to the truth. 这很接近事实。 The resulting type is Seq[Any] . 结果类型为Seq[Any] Unfortunately, this is a completely useless type. 不幸的是,这是一个完全没用的类型。 It's not something you could do anything useful with in a typesafe way, and a good point could be made that Scala shouldn't have allowed this type to be inferred in the first place. 您不能以类型安全的方式做任何有用的事情,而且可以指出,Scala不应首先允许推断此类型。

The solution is not to let it get that far in the first place, but map to something that does have a sensible type. 解决方案不是首先让它走得那么远,而要映射到确实具有明智类型的对象。 The solution shown by Simon is a reasonable approach: 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!")
}

Now mapped is a Seq[Seq[Int]] , and we can do more useful things with it, for example flatten it to a Seq[Int] with mapped.flatten 现在,映射的是Seq[Seq[Int]] ,我们可以用它做更多有用的事情,例如,使用mapped.flatten将其展平为Seq[Int]

But we can get there in one go. 但是我们可以一站式到达那里。 There is an operation called flatMap on Seq[A] that takes a function A => Seq[A] as it's argument, and returns a single Seq[A] . Seq[A]上有一个名为flatMap的操作,该操作将函数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 is now Seq(11, 12, 13, 14, 15) flatmapped现在是Seq(11, 12, 13, 14, 15)


Aside 在旁边

It turns out, by the way, that it's very useful to have this operation on all sorts of parameterized types: (F[A], A => F[A]) => F[A] 事实证明,对各种类型的参数化类型进行此操作非常有用: (F[A], A => F[A]) => F[A]

For example: 例如:

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

or 要么

Future[A].flatMap(a: A => Future[A]): Future[A]

This operation is sometimes called flatMap , and sometimes called bind , and sometimes represented as =>> , and if a type (call it F[A] ) that support this operation, and support another operation that can create an F[A] from an A as well (sometimes called point and sometimes called return ), and follow some conditions on how these operations compose, F[A] forms a Monad 此操作有时称为flatMap ,有时称为bind ,有时表示为=>> ,并且如果某个类型(称为F[A] )支持该操作,并且支持另一种可以从中创建F[A]的操作同样是A (有时称为point ,有时也称为return ),并遵循这些操作的组成条件, F[A]形成Monad

If you already have this list, you may do flatMap to achieve the required result: 如果已经有了此列表,则可以执行flatMap以获得所需的结果:

val list = Seq(11, Seq(12, 13, 14), 15)

val flattened = list.flatMap {
    case x: Int => Seq(x)
    case y: Seq[Int] => y
}

To avoid warnings (although, it'll not help you in making this code type-safe) you may use following: 为了避免警告(尽管这样做对确保代码类型安全无济于事),可以使用以下命令:

val flattened = list.flatMap {
    case x: Int => Seq(x)
    case y: Seq[_] => y.asInstanceOf[Seq[Int]]
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM