Scala Seq包含对于空序列非法或未定义的方法,例如max
为了保护自己,我经常通过将序列包装在一个选项中并将空映射到None来解决问题。可以这样做:
someStore
.giveMeASequence
.wrapInOption map { nonEmpty:Seq[T] =>
nonEmpty.max
} map (_ + 42)
它也可以通过模式匹配或if-else来解决。
这些方法都不易于流畅地使用,坦率地说看起来有点尴尬。
我希望能够做到这样的事情:
library(ggplot2)
dt = data.frame(Chr = c("c1","c1","c1","c2","c2","c2","c3","c3","c3"),
x = c(1,2,3,4,5,6,7,8,9),
y = c(2,4,5,2,3,4,6,6,7))
ggplot(dt, aes(x,y, col=Chr)) +
geom_point(size = 3) +
geom_line() +
facet_grid(. ~ Chr) # remove this to have all lines in same plot
我对在Try monad中包装操作犹豫不决,因为可以预测和避免异常。
我是以错误的方式解决问题吗?
如果没有,是否有任何图书馆方法可以让它不那么尴尬?
答案 0 :(得分:3)
如果您只是想进行转换,为什么不使用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) }
答案 1 :(得分:3)
您可以通过隐式类使用安全方法扩展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)
答案 2 :(得分:3)
正如我在评论中提到的,scalaz NonEmptyList
课程对您有所帮助。通过导入scalaz pimping,您可以访问toNel
上可以调用的List
方法。如果此列表确实为空,则无法继续映射它。如果它不是空的,你的确可以映射它。请考虑以下示例:
import scalaz._
import Scalaz._
val nonEmpty = List(1,2,3)
val result =
nonEmpty.
toNel.
map(_.list.max).
map(_ + 42)
println(result)
如果您运行此代码,它将打印Some(45)
。如果该列表为空,则会产生None
。