Скала: Карта с двумя или более параметров

StackOverflow https://stackoverflow.com/questions/5832520

  •  27-10-2019
  •  | 
  •  

Вопрос

По сути, я ищу самый похожий на скала способ сделать следующее:

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

Все же суммируется более двух вариантов, которые я должен использовать слишком много ifs или использовать какой -то цикл.

РЕДАКТИРОВАТЬ-1:

Во время написания вопроса я придумал своего рода ответ:

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

Это выглядит очень идиоматическим для моего неопытного глаза. Это даже сработало бы с более чем двумя ценностями. Тем не менее, возможно ли сделать то же самое, не преобразуя списки?

Редактировать-2:

Я закончил этим решением (благодаря Зиггистар):

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
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top