假设我有(Option[Long], Option[Long], Option[Long], Option[Long], Option[Long])
类型的项目,并且我想将其转换为(Long, Long, Long, Long, Long)
类型的项目。我希望每个坐标都包含选项的值(如果选项包含"某些"值),否则为零。
通常如果我有Option[Long]
类型的项目,我会做类似的事情
item match {
case Some(n) => n
case None => 0
}
但我不能用5坐标项来做,除非我想列出所有32种可能性。我该怎么做呢?
答案 0 :(得分:4)
简单的解决方案:
item match {
case (a, b, c, d, e) => (a.getOrElse(0), b.getOrElse(0), c.getOrElse(0), d.getOrElse(0), e.getOrElse(0))
}
显然这不是非常通用的。为此,你可能想看看Shapeless,但我会把答案留给常驻专家。 ;)
答案 1 :(得分:2)
使用Shapeless你可以做到:
import shapeless._
import syntax.std.tuple._
import poly._
object defaultValue extends Poly1 {
implicit def defaultOptionLong = at[Option[Long]](_.getOrElse(0L))
}
val tuple : (Option[Long], Option[Long], Option[Long], Option[Long], Option[Long]) =
(Some(1L), None, Some(3L), Some(4L), None)
tuple.map(defaultValue)
// (Long, Long, Long, Long, Long) = (1,0,3,4,0)
如果您不使用Option[Int]
,则需要明确指定类型Option.apply
。(请参阅此question)。
(Option(1L), Option(2L)).map(defaultValue)
// (Long, Long) = (1,2)
(Some(3L), Some(4L)).map(defaulValue) // does not compile
val t : (Option[Long], Option[Long]) = (Some(3L), Some(4L))
t.map(defaultValue)
// (Long, Long) = (3,4)
(Option(5), None).map(defaultValue) // does not compile
val t2 (Option[Long], Option[Long]) = (Option(5), None)
t2.map(defaultValue)
// (Long, Long) = (5,0)
我们还可以为其他类型提供默认值:
object defaultValue extends Poly1 {
implicit def caseLong = at[Option[Long]](_.getOrElse(0L))
implicit def caseInt = at[Option[Int]](_.getOrElse(0))
implicit def caseString = at[Option[String]](_.getOrElse("scala"))
}
val tuple2 : (Option[Int], Option[Long], Option[String]) = (None, None, None)
tuple2.map(defaultValue)
// (Int, Long, String) = (0,0,scala)
修改:需要明确声明Some(5L)
为Option[Long]
的问题可以使用poly函数中的泛型来解决:
objec defaultValue extends Poly1 {
implicit def caseLong[L <: Option[Long]] = at[L](_.getOrElse(0L))
implicit def caseInt[I <: Option[Int]] = at[I](_.getOrElse(0))
implicit def caseString[S <: Option[String]] = at[S](_.getOrElse("scala"))
}
(Some("A"), Some(1), None: Option[Int], None: Option[String]).map(defaultValue)
// (String, Int, Int, String) = (A,1,0,scala)
答案 2 :(得分:1)
您可以这样做:
val res = for {
a <- item._1.orElse(0L)
b <- item._2.orElse(0L)
c <- item._3.orElse(0L)
d <- item._4.orElse(0L)
e <- item._5.orElse(0L)
} yield (a, b, c, d, e)
不是最好的,但易于实施和理解。
答案 3 :(得分:1)
另一种可能的解决方案:
item.productIterator.collect{
case Some(a: Int) => a
case _ => 0
}.toList match {
case List(a,b,c,d,e) => (a,b,c,d,e)
case _ => (0,0,0,0,0) //or throw exception depending on your logic
}