Question

En gros je cherche le plus scala comme façon de faire ce qui suit:

def sum(value1: Option[Int], value2: Option[Int]): Option[Int] = 
  if(value1.isDefined && value2.isDefined) Some(value1.get + value2.get)
  else if(value1.isDefined && value2.isEmpty) value1
  else if(value1.isEmpty && value2.isDefined) value2
  else None

Cela donne une sortie correcte:

sum(Some(5), Some(3))  // result = Some(8)
sum(Some(5), None)     // result = Some(5)
sum(None, Some(3))     // result = Some(3)
sum(None, None)        // result = None

Cependant, pour résumer plus de deux options faudrait que je me sens d'utiliser trop de ifs ou utiliser une sorte de boucle.

EDIT-1:

Tout en écrivant la question que je suis venu avec une sorte de réponse:

def sum2(value1: Option[Int], value2: Option[Int]): Option[Int] = 
  value1.toList ::: value2.toList reduceLeftOption { _ + _ }

Celui-ci semble très idiomatiques à mes yeux inexpérimentés. Ce serait même travailler avec plus de deux valeurs. Cependant, il est possible de faire la même chose sans la conversion des listes?

EDIT-2:

J'ai fini avec cette solution (grâce à ziggystar ):

def sum(values: Option[Int]*): Option[Int] = 
  values.flatten reduceLeftOption { _ + _ }

EDIT-3:

Une autre alternative grâce à Landei :

def sum(values: Option[Int]*): Option[Int] = 
  values collect { case Some(n) => n } reduceLeftOption { _ + _ }
Était-ce utile?

La solution

Que diriez-vous:

scala> def sum(values: Option[Int]*): Option[Int] = values.flatten match {
     | case Nil => None                                                   
     | case l => Some(l.sum)                                              
     | }
sum: (values: Option[Int]*)Option[Int]

scala> sum(Some(1), None)
res0: Option[Int] = Some(1)

scala> sum(Some(1), Some(4))
res1: Option[Int] = Some(5)

scala> sum(Some(1), Some(4), Some(-5))
res3: Option[Int] = Some(0)

scala> sum(None, None)                
res4: Option[Int] = None

Modifier

Peut-être qu'il serait sain d'esprit de revenir 0 si tous les arguments étaient Aucun. Dans ce cas, la fonction réduirait à values.flatten.sum.

Autres conseils

scala> def sum(a: Option[Int], b: Option[Int]) = (a,b) match {
     |   case (Some(x), Some(y)) => Some(x + y)
     |   case (Some(x), None) => Some(x)
     |   case (None, Some(y)) => Some(y)
     |   case _ => None
     | }
sum: (a: Option[Int],b: Option[Int])Option[Int]

scala> sum(Some(5), Some(3))
res0: Option[Int] = Some(8)

scala> sum(Some(5), None)
res1: Option[Int] = Some(5)

scala> sum(None, Some(3))
res2: Option[Int] = Some(3)

scala> sum(None, None)
res3: Option[Int] = None

Une autre solution est:

def sum(values: Option[Int]*): Int = values.collect{case Some(n) => n}.sum

Alors que dans le flatten en cours est nettement plus pratique, la version collect est plus souple, car elle permet d'effectuer les correspondances et d'avoir des conditions de filtrage supplémentaires ou des motifs complexes. Par exemple. imaginez que vous voulez avoir la somme des carrés de tous les nombres pairs en valeurs:

values.collect{case Some(n) if n mod 2 == 0 => n*n}.sum

Vous pouvez le faire très concis en utilisant le fait qu'il existe une instance de Semigroup pour Option qui fait exactement ce que vous voulez. Vous pouvez utiliser scalaz ou chats . Voici un exemple en utilisant cats:

import cats.std.option._
import cats.syntax.semigroup._
import cats.std.int._

Option(1) |+| Option(2) // Some(3)
Option(1) |+| None      // Some(1)
None      |+| Option(2) // Some(2)

Ainsi, votre sum devient:

def sum(v1: Option[Int], v2: Option[Int]): Option[Int] = v1 |+| v2

solution réduite de michael.kebe avec un petit regard à certaines règles mathématiques de base:

def sum(a: Option[Int], b: Option[Int]) = (a,b) match {
  case (None,None) => None
  case _ => Some(a.getOrElse(0)+b.getOrElse(0))
}

scala> sum(Some(5), Some(3))  // result = Some(8)
res6: Option[Int] = Some(8)

scala> sum(Some(5), None)     // result = Some(5)
res7: Option[Int] = Some(5)

scala> sum(None, Some(3))     // result = Some(3)
res8: Option[Int] = Some(3)

scala> sum(None, None)        // result = None
res9: Option[Int] = None
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top