Frage

Grundsätzlich suche ich nach der skalalischsten Möglichkeit, Folgendes zu tun:

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

Dies gibt die richtige Ausgabe:

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

Doch um mehr als zwei Optionen zusammenzufassen, würde ich viel zu viele verwenden ifs oder verwenden Sie eine Art Schleife.

Edit-1:

Während ich die Frage schrieb, stellte ich eine Art Antwort auf:

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

Dieser sieht für mein unerfahrenes Auge sehr idiomatisch aus. Dies würde sogar mit mehr als zwei Werten funktionieren. Ist jedoch möglich, dasselbe zu tun, ohne in Listen zu konvertieren?

Edit-2:

Am Ende hatte ich diese Lösung (danke an ZigyStar):

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

Edit-3:

Ein weiterer Alternative Dank an Landei:

def sum(values: Option[Int]*): Option[Int] = 
  values collect { case Some(n) => n } reduceLeftOption { _ + _ }
War es hilfreich?

Lösung

Wie wäre es mit:

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

Bearbeiten

Vielleicht wäre es gesund, 0 zurückzukehren, wenn alle Argumente keine wären. In diesem Fall würde sich die Funktion aufnehmen auf values.flatten.sum.

Andere Tipps

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

Eine andere Lösung ist:

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

Während im aktuellen Fall flatten ist eindeutig bequemer, die collect Die Version ist flexibler, da sie Zuordnungen ausführen und zusätzliche Filterbedingungen oder komplexe Muster aufweisen können. ZB stellen Sie sich vor, Sie möchten die Summe der Quadrate aller gleichmäßigen Zahlen in Werten haben:

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

Sie können es mit der Tatsache, dass es eine gibt, sehr präzise machen Semigroup Instanz für Option Das tut genau das, was Sie wollen. Sie können verwenden Scalaz oder Katzen. Hier ist ein Beispiel verwendet 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)

Also dein sum wird:

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

Reduzierte Lösung von Michael.kebe mit ein wenig Blick auf einige grundlegende mathematische Regeln:

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
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top