flatMap和filter的组合是什么?

时间:2016-10-21 17:49:47

标签: scala

在scala集合中,有一个collect方法,它是map和filter的组合。

还有另一种方法是flatMap和filter的组合吗?

这是我想要做的事情

val myList: List[Int] = ....
val x = myList.flatMap { id =>               
  val r : Option[List[Int]] = obj.foo(id)
  r
}

现在,scala编译器告诉我x的类型是List[List[Int]]

但我想要List[Int]

如果我将代码更改为

val myList: List[Int] = ....
val x = myList.flatMap { id =>               
  val r : Option[List[Int]] = obj.foo(id).get
  r
}

然后我得到了我想要的东西。但我不想做。所以我想要一个干净简洁的方法来做一个flatMap,同时过滤掉None的项目。

我也可以

val myList: List[Int] = ....
val result = myList.flatMap { id =>               
  val r : Option[List[Int]] = obj.foo(id).getOrElse(List[Int]())
  r
}

但这仍然非常冗长。

4 个答案:

答案 0 :(得分:3)

好吧,如果您在使用flatMap时尝试过滤,可以轻松地执行类似

的操作
List(1, 2, 3).flatMap {
  case n if n > 1 => List.fill(n)(n.toString)
  case _ => Nil
}
// result: List("2", "2", "3", "3", "3")

在您的具体案例中:

myList.flatMap { id => obj.foo(id) match {
  case Some(list) => list
  case None => Nil
}}

甚至更短

myList.flatMap(obj.foo(_).getOrElse(Nil))

答案 1 :(得分:1)

我认为 for 表达式可以解决这个问题:

val myList: List[Int] = ....
val x = for {
    id <- myList
    r <- obj.foo(id)
} yield r

实际上,表达式已翻译为flatMapmapfilter(请参阅http://docs.scala-lang.org/tutorials/FAQ/yield.html

答案 2 :(得分:0)

如果要将.flatten添加到最后,您的初始代码将完美无缺。

以下是我的写作方式:

val x1: List[Int] = myList.flatMap(obj.foo).flatten

或者如果您出于某种原因确实需要collect,那么如下:

val x2: List[Int] = myList.map(obj.foo).collect{
  case Some(data) => data
}.flatten

完整的来源是:

object Test3 extends App {
  object obj {
    def foo(i: Int) = (0 to i).toList match {
      case Nil => None
      case nonEmpty => Some(nonEmpty)
    }
  }

  val myList: List[Int] = (0 to 3).toList
  val x = myList.flatMap { id =>
    val r : Option[List[Int]] = obj.foo(id)
    r
  }.flatten

  val x1: List[Int] = myList.flatMap(obj.foo).flatten
  val x2: List[Int] = myList.map(obj.foo).collect{
    case Some(data) => data
  }.flatten
}

答案 3 :(得分:0)

如果知道空状态(filter / flatMap),

None实际上可以通过List.empty表达,因此flatMap比{filter更通用1}}(至少ListOption s)。您的问题是需要应用两次:

myList.flatMap(obj.foo).flatMap(x => x)

或只是:

myList.flatMap(obj.foo).flatten

只是一个简单的说明:如果您有List[List[T]]类型,或更常见的M[M[T]],并且您希望获得M[T],则通常会涉及flatMap / {{1} }

示例:

flatten