获取每个字段作为可选对象的选项

时间:2019-01-09 08:10:35

标签: scala options

我有一个类似的案例类

case class EmotionData(
      fearful: Double,
      angry: Double,
      sad: Double,
      neutral: Double,
      disgusted: Double,
      surprised: Double,
      happy: Double
    )

我收到一个Option[EmotionData],我需要每个情感数据作为Option [Double]。

我所做的是:

val (fearful, angry, sad, neutral, disgusted, surprised, happy) = videoResult.emotion match {
        case Some(e) => (Some(e.fearful), Some(e.angry), Some(e.sad), Some(e.neutral), Some(e.disgusted), Some(e.surprised), Some(e.happy))
        case None => (None, None, None, None, None, None, None)
      }

这样,我将每个字段都作为Option [Double]值。

但是在Scala中没有办法做到这一点,我可以遍历对象的所有字段并提取它们而无需重写每个字段吗?

4 个答案:

答案 0 :(得分:4)

这是一种稍微不同的方法,也许更可口。

val vidEmo :Option[EmotionData] = videoResult.emotion

val (fearful, angry, sad, neutral, disgusted, surprised, happy) =
  (vidEmo.map(_.fearful)
  ,vidEmo.map(_.angry)
  ,vidEmo.map(_.sad)
  ,vidEmo.map(_.neutral)
  ,vidEmo.map(_.disgusted)
  ,vidEmo.map(_.surprised)
  ,vidEmo.map(_.happy))

但是实际上,您应该只保留vidEmo并在需要时提取所需的内容。

答案 1 :(得分:1)

是的,有一种方法可以使用productIterator遍历对象的字段。看起来像这样:

val List(fearful, angry, sad, neutral, disgusted, surprised, happy) =
  videoResult.emotion.map(_.productIterator.map(f => Some(f.asInstanceOf[Double])).toList)
    .getOrElse(List.fill(7)(None))

如您所见,这并不比您已经拥有的要好得多,并且更容易出错。问题在于字段的数量和顺序在您指定的结果中是明确的,因此可以自动执行的操作数量有限制。这仅适用于所有字段的类型相同。

我个人会尽可能将值保留为Option[EmotionData],并根据需要选择单个值,例如:

val opt = videoResult.emotion

val fearful = opt.map(_.fearful) // Option[Double]
val angry = opt.map(_.angry) // Option[Double]
val sad = opt.map(_.sad) // Option[Double]

val happy = opt.fold(0)(_.happy) // Double, default is 0 if opt is None

val ok = opt.forall(e => e.happy > e.sad) // True if emotion not set or more happy than sad

val disgusted = opt.exists(_.disgusted > 1.0) // True if emotion is set and disgusted value is large

答案 2 :(得分:0)

也许是吗?

case class EmotionData(
                        fearful: Double,
                        angry: Double,
                        sad: Double,
                        neutral: Double,
                        disgusted: Double,
                        surprised: Double,
                        happy: Double
                      )

val s = Some(EmotionData(1,2,3,4,5,6,7))
val n:Option[EmotionData] = None

val emotionsOpt = s.map { x =>
  x.productIterator.toVector.map(x => Some(x.asInstanceOf[Double]))
}.getOrElse(List.fill(7)(None))

// Or if you want an iterator:
val emotionsOptItr = n.map { x =>
  x.productIterator.map(x => Some(x.asInstanceOf[Double]))
}.getOrElse(List.fill(7)(None))


println(emotionsOpt)
println(emotionsOptItr)

这将导致:

Vector(Some(1), Some(2), Some(3), Some(4), Some(5), Some(6), Some(7))
List(None, None, None, None, None, None, None)

答案 3 :(得分:-1)

您可以执行以下操作:

val defaultEmotionData=(0.0,0.0,0.0,0.0,0.0,0.0,0.0)

object Solution1 extends App{
 case class EmotionData(
                          fearful: Double,
                          angry: Double,
                          sad: Double,
                          neutral: Double,
                          disgusted: Double,
                          surprised: Double,
                          happy: Double
                        )

  case class EmotionDataOption(
                                fearfulOpt: Option[Double],
                                angryOpt: Option[Double],
                                sadOpt: Option[Double],
                                neutralOpt: Option[Double],
                                disgustedOpt: Option[Double],
                                surprisedOpt: Option[Double],
                                happyOpt: Option[Double]
                              )

  val emotion = Some(EmotionData(1.2, 3.4, 5, 6, 7.8, 3, 12))

  val ans: EmotionDataOption = emotion.getOrElse(defaultEmotionData).toOption

  implicit class ToOption(emotionData: EmotionData) {
    def toOption = EmotionDataOption(Some(emotionData.fearful), Some(emotionData.angry), Some(emotionData.sad), Some(emotionData
        .neutral), Some(emotionData.disgusted), Some(emotionData.surprised), Some(emotionData.happy))
  }
}

现在您将在任何位置使用EmotionData类型的对象,都可以在该对象上使用toOption,它将其值转换为EmotionDataOption,该值将具有Option [Double]值。

如果您将返回Tuple7,那么访问值将很困难,这就是为什么我认为将其转换为另一个case class EmotionDataOption是一个好主意,并且您将能够使用参数名称。