如何从List[Option]过滤掉None?

128
如果我在Scala中有一个List [Option [A]],那么筛选掉None值的惯用方法是什么?
一种方法是使用以下代码:
val someList: List[Option[String]] = List(Some("Hello"), None, Some("Goodbye"))
someList.filter(_ != None)

有没有更“惯用”的方式?这似乎相当简单。


1
相关链接:https://dev59.com/b2445IYBdhLWcg3ws8dq - dskrvk
4个回答

193

如果您想同时去掉选项,可以使用 flatten

scala> someList.flatten
res0: List[String] = List(Hello, Goodbye)

30
我想补充一点,flatMap可以用来处理除了None之外的列表元素,类似于someList.flatten.map,因为我们经常希望处理这些元素而不仅仅是为了好玩而flatten列表。 - Frank
有没有等效的 flatForeach 类型方法? - cdmckay
1
如果你的集合是不可变的,flatMap 就可以解决问题。如果你的集合是可变的,那么不行。 - Nicolas
我发现在某些情况下,为了使其正常工作,需要使用类型注释。 - matanster
@Frank 我认为flatMap的行为更像是map.flatten而不是flatten.map。如果map函数返回None,它将从最终结果中删除。 - Hunger
显示剩余4条评论

22

someList.filter(_.isDefined) 如果你希望结果类型保持为 List[Option[A]]


5
cats 库还提供了 flattenOption 方法,它可以将任意的 F[Option[A]] 转换成 F[A](其中F[_] 是一个 FunctorFilter)。
import cats.implicits._

List(Some(1), Some(2), None).flattenOption == List(1, 2)

1
为什么在标准库中已经有flatten函数的情况下,cats还要增加这个函数呢?它是做了一些额外的操作吗? - Mojo
@Mojo的版本更通用,因为它可以为任何类型提供此功能,只要定义了FunctorFilter类型类(例如,cats为映射提供了这样的实例,因此您可以在Map[A,Option[B]]上使用它,而标准库中没有flatten)。 - crater2150

0

如果您有一个比字符串更复杂的对象的选项列表,可能像这样:

case class Thing(name: String, number: Int)

val someSequence: Seq[Option[Thing]] = Seq(
  Some(Thing("Hello", 1)),
  None,
  Some(Thing("Goodbye", 2)),
  None
)

你可以使用flatMap来链接内部值的映射:

scala> someSequence.flatMap(_.map(_.name))
val res2: Seq[String] = List(Hello, Goodbye)

但是在我看来,@Nicolas上面的答案更加简洁,因为你可以这样做:

scala> someSequence.flatten.map(_.name)
val res3: Seq[String] = List(Hello, Goodbye)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接