选项列表:相当于 Scala 中的序列?

发布于 2024-11-25 11:10:25 字数 395 浏览 2 评论 0原文

Haskell 的 sequence< 等价于什么/code>在 Scala 中?我想将选项列表变成列表选项。如果任何选项为 None,则其结果应为 None

List(Some(1), None, Some(2)).???     --> None
List(Some(1), Some(2), Some(3)).???  --> Some(List(1, 2, 3))

What is the equivalent of Haskell's sequence in Scala? I want to turn list of options into an option of list. It should come out as None if any of the options is None.

List(Some(1), None, Some(2)).???     --> None
List(Some(1), Some(2), Some(3)).???  --> Some(List(1, 2, 3))

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

秋心╮凉 2024-12-02 11:10:25

Scalaz 定义了序列

下面是一个示例:

scala> import scalaz._
import scalaz._

scala> import Scalaz._
import Scalaz._

scala> List(Some(1), None, Some(2)).sequence
res0: Option[List[Int]] = None

scala> List(some(1), some(2), some(3)).sequence
res1: Option[List[Int]] = Some(List(1, 2, 3))

请注意,在第二个示例中,您必须使用 Scalaz 的 some 函数来创建 Some ——否则,List 将被构造为 List[Some[Int]],这会导致此错误:

scala> List(Some(1), Some(2), Some(3)).sequence
<console>:14: error: could not find implicit value for parameter n: scalaz.Applicative[N]
       List(Some(1), Some(2), Some(3)).sequence

Scalaz some(a ) 和 none 函数创建 Option[A] 类型的 Some 和 None 值。

Scalaz defines sequence.

Here's an example:

scala> import scalaz._
import scalaz._

scala> import Scalaz._
import Scalaz._

scala> List(Some(1), None, Some(2)).sequence
res0: Option[List[Int]] = None

scala> List(some(1), some(2), some(3)).sequence
res1: Option[List[Int]] = Some(List(1, 2, 3))

Note that in the second example, you have to use Scalaz's some function to create a Some -- otherwise, the List is constructed as List[Some[Int]], which results in this error:

scala> List(Some(1), Some(2), Some(3)).sequence
<console>:14: error: could not find implicit value for parameter n: scalaz.Applicative[N]
       List(Some(1), Some(2), Some(3)).sequence

The Scalaz some(a) and none functions create Some and None values of type Option[A].

蹲在坟头点根烟 2024-12-02 11:10:25

如果您想要一个仅针对 List 和 Option 而不是一般 monad 的解决方案,那么以下内容即可完成工作,

def sequence[T](l : List[Option[T]]) = 
  if (l.contains(None)) None else Some(l.flatten)

REPL 会话,

scala> sequence(List(Some(1), None, Some(2)))
res2: Option[List[Int]] = None

scala> sequence(List(Some(1), Some(2), Some(3)))
res3: Option[List[Int]] = Some(List(1, 2, 3)) 

更新 20/8/2014

只需使用 Scalaz ...

If you want a solution for just List and Option rather a general monad then following will do the job,

def sequence[T](l : List[Option[T]]) = 
  if (l.contains(None)) None else Some(l.flatten)

REPL session,

scala> sequence(List(Some(1), None, Some(2)))
res2: Option[List[Int]] = None

scala> sequence(List(Some(1), Some(2), Some(3)))
res3: Option[List[Int]] = Some(List(1, 2, 3)) 

Update 20/8/2014

Just use Scalaz ...

泛泛之交 2024-12-02 11:10:25

这是与上面相同的函数,使用了 FoldRight 和 map/ flatmap 的组合,只需遍历列表一次:

  def sequence[A](lo: List[Option[A]]): Option[List[A]] = 
    lo.foldRight (Option(List[A]())) { (opt, ol) => 
      ol flatMap (l => opt map (o => o::l))
    }

或者,如果您更喜欢 for 理解版本:

  def sequence2[A](lo: List[Option[A]]): Option[List[A]] = 
    lo.foldRight (Option(List[A]())) { (opt, ol) =>
      for {l <- ol; o <- opt} yield (o::l)
    }

Here is the same function as above using a combination of foldRight and map/ flatmap that only has to traverse the list once:

  def sequence[A](lo: List[Option[A]]): Option[List[A]] = 
    lo.foldRight (Option(List[A]())) { (opt, ol) => 
      ol flatMap (l => opt map (o => o::l))
    }

Or, if you prefer the for comprehension version:

  def sequence2[A](lo: List[Option[A]]): Option[List[A]] = 
    lo.foldRight (Option(List[A]())) { (opt, ol) =>
      for {l <- ol; o <- opt} yield (o::l)
    }
白馒头 2024-12-02 11:10:25

首先,我建议您查看 API列表的文档

至于解决方案,这可能不是最优雅的方法,但它会起作用(并且没有外部依赖项):

// a function that checks if an option is a None
def isNone(opt:Option[_]) = opt match {
  case None => true
  case _ => false
}

//templated for type T so you can use whatever Options
def optionifyList[T](list:List[Option[T]]) = list.exists(isNone) match {
  case true => None
  case false => Some(list.flatten)
}

并且进行测试以确保......

scala> val hasNone = Some(1) :: None :: Some(2) :: Nil
hasNone: List[Option[Int]] = List(Some(1), None, Some(2))

scala> val hasSome = Some(1) :: Some(2) :: Some(3) :: Nil
hasSome: List[Some[Int]] = List(Some(1), Some(2), Some(3))

scala> optionifyList(hasSome)
res2: Option[List[Int]] = Some(List(1, 2, 3))

scala> optionifyList(hasNone)
res3: Option[List[Int]] = None

First off, I recommend that you check out the API docs for List.

As for a solution, this may not be the most graceful way to do it, but it'll work (and with no external dependencies):

// a function that checks if an option is a None
def isNone(opt:Option[_]) = opt match {
  case None => true
  case _ => false
}

//templated for type T so you can use whatever Options
def optionifyList[T](list:List[Option[T]]) = list.exists(isNone) match {
  case true => None
  case false => Some(list.flatten)
}

And a test just to be sure...

scala> val hasNone = Some(1) :: None :: Some(2) :: Nil
hasNone: List[Option[Int]] = List(Some(1), None, Some(2))

scala> val hasSome = Some(1) :: Some(2) :: Some(3) :: Nil
hasSome: List[Some[Int]] = List(Some(1), Some(2), Some(3))

scala> optionifyList(hasSome)
res2: Option[List[Int]] = Some(List(1, 2, 3))

scala> optionifyList(hasNone)
res3: Option[List[Int]] = None
绮烟 2024-12-02 11:10:25

也许这有帮助,因为它只遍历一次并使用递归

def sequence[A](a: List[Option[A]]): Option[List[A]] =
a match {
  case Nil => Some(Nil)
  case h :: rest => h.flatMap(x => sequence(rest).map(x :: _))
}

Maybe this helps, as it traverses once only and use recursion

def sequence[A](a: List[Option[A]]): Option[List[A]] =
a match {
  case Nil => Some(Nil)
  case h :: rest => h.flatMap(x => sequence(rest).map(x :: _))
}
み青杉依旧 2024-12-02 11:10:25

通过 for 理解,这非常简单:

val x : Option[String] = Option("x")
val y : Option[String] = Option("y")
val z : Option[String] = None

// Result -> a: Option[List[String]] = None    
val a = for {
  x <- x
  y <- y
  z <- z
} yield List(x,y,z)    

// Result -> b: Option[List[String]] = Some(List(x, y))    
val b = for {
  x <- x
  y <- y
} yield List(x,y)

This is very simple with a for comprehension:

val x : Option[String] = Option("x")
val y : Option[String] = Option("y")
val z : Option[String] = None

// Result -> a: Option[List[String]] = None    
val a = for {
  x <- x
  y <- y
  z <- z
} yield List(x,y,z)    

// Result -> b: Option[List[String]] = Some(List(x, y))    
val b = for {
  x <- x
  y <- y
} yield List(x,y)
一页 2024-12-02 11:10:25

因为无论如何你都需要展平,所以先做...

def sequence(lo: List[Option[A]]): Option[List[A]] = lo.flatten match {
    la: List[A] if(la.length == lo.length) => Some(la)
    _ => None
}

尾递归可能是最快的

Since you need to flatten anyway, just do it first...

def sequence(lo: List[Option[A]]): Option[List[A]] = lo.flatten match {
    la: List[A] if(la.length == lo.length) => Some(la)
    _ => None
}

tail recursion might be quickest

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文