Как суммировать множество [ValidatedNel [String, Double]]? - PullRequest
3 голосов
/ 13 июня 2019

У меня есть это:

Set[ValidatedNel[String, Double]] 

, и я хотел бы сложить в нем двойные числа, чтобы получить:

ValidatedNel[String, Double]

Если некоторые элементы в значениях, то я хотел быесть совпадающие строки.

Я играл с Set.sum и Numeric безрезультатно ...

Вот тест того, чего я хотел бы достичь:

  test("Summing ValidatedNel works") {
    val val1: ValidatedNel[String, Double] = Valid(1.0)
    val val2: ValidatedNel[String, Double] = Valid(2.0)
    val values: Set[ValidatedNel[String, Double]] = Set(val1, val2)

    val validatedNelNumeric: Numeric[ValidatedNel[String, Double]] = ???
    val sum = values.sum(validatedNelNumeric)

    assert(sum == Valid(3.0))
  }

Мне не удается создать validatedNelNumeric ...

1 Ответ

5 голосов
/ 13 июня 2019

Для начала: в данном случае немного странно использовать набор (для набора значений Validated[..., Double]).Какая часть семантики Set вас волнует?Неупорядоченность?Уникальность?

В общем, самый простой способ суммировать элементы, имеющие экземпляр Monoid, - это использовать метод combineAll для вещей с экземпляром Foldable, например, List (ноне Set).

import cats.data.{ Validated, ValidatedNel }
import cats.instances.double._, cats.instances.list._
import cats.syntax.foldable._
// or just import cats.implicits._

val val1: ValidatedNel[String, Double] = Validated.valid(1.0)
val val2: ValidatedNel[String, Double] = Validated.valid(2.0)
val bad1: ValidatedNel[String, Double] = Validated.invalidNel("foo")
val bad2: ValidatedNel[String, Double] = Validated.invalidNel("bar")

val values = Set(val1, val2)
val withSomeBadOnes = Set(val1, bad1, val2, bad2)

А потом:

scala> values.toList.combineAll
res0: cats.data.ValidatedNel[String,Double] = Valid(3.0)

scala> withSomeBadOnes.toList.combineAll
res1: cats.data.ValidatedNel[String,Double] = Invalid(NonEmptyList(foo, bar))

Я думаю, это то, что вы подразумеваете под "Если некоторые элементы в значениях, то я хотел бы иметьсоответствующие строки "?

Вы также можете использовать SortedSet, поскольку Cats предоставляет экземпляр Foldable для SortedSet, но это не так удобно:

scala> import cats.implicits._
import cats.implicits._

scala> import scala.collection.immutable.SortedSet
import scala.collection.immutable.SortedSet

scala> (SortedSet.empty[ValidatedNel[String, Double]] ++ values).combineAll
res2: cats.data.ValidatedNel[String,Double] = Valid(3.0)

scala> (SortedSet.empty[ValidatedNel[String, Double]] ++ withSomeBadOnes).combineAll
res3: cats.data.ValidatedNel[String,Double] = Invalid(NonEmptyList(bar, foo))

Вы также можете использоватьстандартный fold и оператор |+| для моноидов:

scala> values.fold(Validated.valid(0.0))(_ |+| _)
res4: cats.data.ValidatedNel[String,Double] = Valid(3.0)

Подводя итог: вы не можете позвонить combineAll непосредственно на ваш Set, поскольку Cats не предоставляет Foldable для Set.Я бы посоветовал тщательно пересмотреть использование Set в любом случае, но если вы решите придерживаться его, у вас есть несколько вариантов: преобразовать в List или SortedSet, как у меня выше, используйте стандартный fold на Set, или, наконец, напишите свой собственный Foldable[Set] или используйте тот из alleycats.

...