質問
基本的に、私は以下を行うための最もScalaのような方法を探しています:
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
これにより、正しい出力が得られます。
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
しかし、2つ以上のオプションを合計するには、あまりにも多く使用する必要があります if
sまたは何らかのループを使用します。
編集1:
質問を書いている間、私は一種の答えを思いつきました:
def sum2(value1: Option[Int], value2: Option[Int]): Option[Int] =
value1.toList ::: value2.toList reduceLeftOption { _ + _ }
これは私の経験の浅い目と非常に慣用的に見えます。これは、3つ以上の値でも機能します。しかし、リストに変換せずに同じことをすることは可能ですか?
編集2:
私はこの解決策になりました(ありがとう Ziggystar):
def sum(values: Option[Int]*): Option[Int] =
values.flatten reduceLeftOption { _ + _ }
編集-3:
別の代替案のおかげです ランダイ:
def sum(values: Option[Int]*): Option[Int] =
values collect { case Some(n) => n } reduceLeftOption { _ + _ }
解決
どうですか:
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
編集
すべての引数が存在しない場合、0を返すのは正気かもしれません。その場合、関数はに減少します values.flatten.sum
.
他のヒント
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
別の解決策は次のとおりです。
def sum(values: Option[Int]*): Int = values.collect{case Some(n) => n}.sum
現在の場合 flatten
明らかに便利です collect
バージョンは、マッピングを実行し、追加のフィルター条件または複雑なパターンを持つことができるため、より柔軟です。たとえば、価値のすべての偶数の正方形の合計を持ちたいと想像してください。
values.collect{case Some(n) if n mod 2 == 0 => n*n}.sum
あなたは、あるという事実を使用して非常に簡潔にすることができます Semigroup
のインスタンス Option
それはあなたが望むことを正確に行います。使用できます スカラズ また 猫. 。使用の例を次に示します 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)
だからあなた sum
なる:
def sum(v1: Option[Int], v2: Option[Int]): Option[Int] = v1 |+| v2
Michael.kebeの解決策は、いくつかの基本的な数学的ルールを少し見ています。
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
所属していません StackOverflow