将 Seq[T] 转换为 Option[Seq[T]]
Converting Seq[T] into Option[Seq[T]]
Scala Seq 包含对空序列非法或未定义的方法,例如 max
为了保护自己免受这种情况的影响,我经常通过将序列包装在一个选项中并将空映射到 None 来解决这个问题。可以这样做:
def wrap[T](s: Seq[T]): Option[Seq[T]] =
s.headOption map { _ => s }
也可以通过模式匹配或者if-else来解决。
None 的方法很容易以流畅的方式使用,坦率地说似乎有点笨拙。
我希望能够做这样的事情:
someStore
.giveMeASequence
.wrapInOption map { nonEmpty:Seq[T] =>
nonEmpty.max
} map (_ + 42)
我犹豫是否将操作包装在 Try monad 中,因为可以预测和避免异常。
我是不是以错误的方式解决了问题?
如果没有,是否有任何库方法可供我使用以减少尴尬?
如果您只想进行转换,为什么不使用 if/else?
def wrap[A](s: Seq[A]) = if (s.isEmpty) None else Some(s)
或者,您可以定义自己的 maxOpt
方法:
implicit def seqWithMaxOpt[A:Ordering](s:Seq[A]) =
new { def maxOpt = Try(s.max).toOption }
然后这样称呼它
val s:Seq[Int] = Seq()
s.maxOpt
以同样的方式,您可以添加一个将序列包装在选项中的方法:
implicit def seqWithOptionWrapping[A](s:Seq[A]) =
new { def wrapInOption = if (s.isEmpty) None else Some(s) }
您可以通过隐式 class 使用您的安全方法扩展 Seq
:
implicit class SafeSeq[T](s: Seq[T]) {
def safeMax(implicit cmp: Ordering[T]): Option[T] =
if (s.isEmpty) None
else Some(s.max)
//other safe operations you want
}
println(Seq.empty[Int].safeMax.map(_ + 42)) // None
println(Seq(1).safeMax.map(_ + 42)) // Some(43)
正如我在评论中提到的,scalaz NonEmptyList
class 可能对您有所帮助。通过导入 scalaz pimping,您可以访问可以在 List
上调用的 toNel
方法。如果这个列表确实是空的,你不能继续映射它。如果它不是空的,你确实可以映射它。考虑以下示例:
import scalaz._
import Scalaz._
val nonEmpty = List(1,2,3)
val result =
nonEmpty.
toNel.
map(_.list.max).
map(_ + 42)
println(result)
如果您 运行 此代码,它将打印 Some(45)
。如果该列表为空,则会导致 None
.
Scala Seq 包含对空序列非法或未定义的方法,例如 max
为了保护自己免受这种情况的影响,我经常通过将序列包装在一个选项中并将空映射到 None 来解决这个问题。可以这样做:
def wrap[T](s: Seq[T]): Option[Seq[T]] =
s.headOption map { _ => s }
也可以通过模式匹配或者if-else来解决。
None 的方法很容易以流畅的方式使用,坦率地说似乎有点笨拙。
我希望能够做这样的事情:
someStore
.giveMeASequence
.wrapInOption map { nonEmpty:Seq[T] =>
nonEmpty.max
} map (_ + 42)
我犹豫是否将操作包装在 Try monad 中,因为可以预测和避免异常。
我是不是以错误的方式解决了问题?
如果没有,是否有任何库方法可供我使用以减少尴尬?
如果您只想进行转换,为什么不使用 if/else?
def wrap[A](s: Seq[A]) = if (s.isEmpty) None else Some(s)
或者,您可以定义自己的 maxOpt
方法:
implicit def seqWithMaxOpt[A:Ordering](s:Seq[A]) =
new { def maxOpt = Try(s.max).toOption }
然后这样称呼它
val s:Seq[Int] = Seq()
s.maxOpt
以同样的方式,您可以添加一个将序列包装在选项中的方法:
implicit def seqWithOptionWrapping[A](s:Seq[A]) =
new { def wrapInOption = if (s.isEmpty) None else Some(s) }
您可以通过隐式 class 使用您的安全方法扩展 Seq
:
implicit class SafeSeq[T](s: Seq[T]) {
def safeMax(implicit cmp: Ordering[T]): Option[T] =
if (s.isEmpty) None
else Some(s.max)
//other safe operations you want
}
println(Seq.empty[Int].safeMax.map(_ + 42)) // None
println(Seq(1).safeMax.map(_ + 42)) // Some(43)
正如我在评论中提到的,scalaz NonEmptyList
class 可能对您有所帮助。通过导入 scalaz pimping,您可以访问可以在 List
上调用的 toNel
方法。如果这个列表确实是空的,你不能继续映射它。如果它不是空的,你确实可以映射它。考虑以下示例:
import scalaz._
import Scalaz._
val nonEmpty = List(1,2,3)
val result =
nonEmpty.
toNel.
map(_.list.max).
map(_ + 42)
println(result)
如果您 运行 此代码,它将打印 Some(45)
。如果该列表为空,则会导致 None
.