J'ai une classe de cas qui ressemble à ceci
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) }
Je reçois une Option [EmotionData]
et j'ai besoin de chaque donnée d'émotion comme Option [Double].
/ p>
Ce que j'ai fait, c'est:
case class EmotionData( fearful: Double, angry: Double, sad: Double, neutral: Double, disgusted: Double, surprised: Double, happy: Double )
De cette façon, j'ai chaque champ comme valeur Option [Double].
Mais n'y a-t-il pas un moyen de faire cela dans Scala où je peux parcourir tous les champs d'un objet et les extraire sans réécrire chaque champ?
4 Réponses :
Vous pouvez faire quelque chose comme ça:
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)) } }
Maintenant, où que vous soyez, vous aurez un objet de type EmotionData, vous pouvez utiliser toOption dessus et il convertira ses valeurs en EmotionDataOption qui aura des valeurs Option [Double].
Si vous retournez Tuple7
alors il sera difficile d'accéder aux valeurs, c'est pourquoi je pense le convertir en une autre classe de cas EmotionDataOption code > est une bonne idée et vous pourrez accéder facilement aux valeurs avec le nom du paramètre.
Si vous obtenez un vote négatif, la première chose à faire est de vérifier si vous avez donné une réponse claire et simple à la question. Votre solution est trop compliquée, elle ne donne pas la bonne réponse et ne «parcourt pas tous les champs d'un objet». La vraie question est de savoir pourquoi a-t-il obtenu des votes positifs?!
@Tim merci d'avoir répondu. En fait, si vous lisez toute la question, il n’existe pas de moyen de le faire dans scala où l’auteur peut parcourir les champs d’un objet et les extraire «SANS RÉÉCRITER CHAQUE CHAMP». Et comme nous pouvons le voir, l'auteur propose simplement qu'il ne sait pas qu'il existe ce genre de moyen ou non, c'est juste une pensée de sa part, il n'est pas sûr et je pense qu'il peut y avoir plusieurs réponses à une question. Et ma réponse résout le but, je ne trouve pas l'itération bonne pour le scénario. Et pouvez-vous me dire en quoi la réponse est trop compliquée?
Votre réponse est de 16 lignes et donne la mauvaise réponse, la mienne est de 3 lignes.
Tout d'abord, cela ne donne pas la mauvaise réponse et la deuxième chose, ce n'est pas à propos de LOC et la troisième chose est que vos 3 lignes de code ne sont pas réutilisables et si vous voyez vraiment ma réponse, la partie de la classe implicite fait le travail et le d'autres choses sont pour rendre les choses faciles comme une autre classe de cas et si vous voyez que cette classe implicite est de 3 lignes, je mets tout simplement tout dans le même objet afin que si l'auteur veut vérifier la solution, il puisse l'exécuter directement. C’est donc aussi une solution à 3 lignes. Je pense que vous êtes nouveau sur scala. @Tim
@Tim et que se passe-t-il si nous avons 1000 objets de ce type dans l'état actuel, nous devrons écrire 3000 LOC par votre solution et pour le mien, ce sera toujours 3 en tant que moi et 16 en tant que lignes de code
Regardez la solution OP lorsque l ' Option [EmotionData]
est Aucune
et comparez-la avec votre solution. Et regardez la ligne qui dit "Je reçois une Option [EmotionData]
et j'ai besoin de chaque donnée d'émotion comme Option [Double]
"
@Tim c'est ce qu'il a essayé il veut une meilleure solution sinon il n'a pas besoin de poser la question sur le stackoverflow.
Peut-être ceci?
Vector(Some(1), Some(2), Some(3), Some(4), Some(5), Some(6), Some(7)) List(None, None, None, None, None, None, None)
Ce qui donne:
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)
Pourquoi les votes négatifs? pouvez-vous expliquer pourquoi? et puis je pourrais essayer d'améliorer la réponse.
Votre réponse initiale a été rejetée car elle était très médiocre. Vous l'avez amélioré un peu après la publication d'autres réponses, mais vous ne renvoyez toujours pas les valeurs de Option [Double]
dans le cas où s
vaut None < / code>.
Voici une approche légèrement différente qui pourrait être, peut-être, un peu plus acceptable.
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))
Mais vraiment, vous devriez simplement garder vidEmo code> autour et extrayez ce dont vous avez besoin quand vous en avez besoin.
Oui, il existe un moyen de parcourir les champs d'un objet en utilisant productIterator
. Cela ressemblerait à quelque chose comme ceci:
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
Comme vous pouvez le voir, ce n'est pas beaucoup mieux que ce que vous avez déjà, et est plus sujet aux erreurs. Le problème est que le nombre et l'ordre des champs sont explicites dans le résultat que vous avez spécifié, il y a donc des limites à combien cela peut être automatisé. Et cela ne fonctionne que parce que le type de tous les champs est le même.
Personnellement, je garderais la valeur comme Option [EmotionData]
aussi longtemps que possible, et choisirais des valeurs individuelles au besoin, comme ceci:
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))