Подтвердить что ты не робот

Что такое синтаксис Scala для суммирования списка объектов?

Например

case class Blah(security: String, price: Double)
val myList = List(Blah("a", 2.0), Blah("b", 4.0))
val sum = myList.sum(_.price) // does not work

Каков синтаксис для получения суммы?

4b9b3361

Ответ 1

Попробуйте следующее:

val sum = myList.map(_.price).sum

Или поочередно:

val sum = myList.foldLeft(0.0)(_ + _.price)

Кажется, вы пытаетесь использовать этот метод:

def sum [B >: A] (implicit num: Numeric[B]): B

и компилятор не может понять, как функция, которую вы предоставляете, является экземпляром Numeric, потому что это не так.

Ответ 2

Scalaz имеет этот метод под именем foldMap. Подпись:

def M[A].foldMap[B](f: A => B)(implicit f: Foldable[M], m: Monoid[B]): B

Использование:

scala> case class Blah(security: String, price: Double)
defined class Blah

scala> val myList = List(Blah("a", 2.0), Blah("b", 4.0))
myList: List[Blah] = List(Blah(a,2.0), Blah(b,4.0))

scala> myList.foldMap(_.price)
res11: Double = 6.0

B здесь не обязательно должен быть числовой тип. Это может быть любой моноид. Пример:

scala> myList.foldMap(_.security)
res12: String = ab

Ответ 3

В качестве альтернативы примеру Scapase missingfaktor, если вы действительно хотите суммировать список объектов (в отличие от сопоставления каждого из них с числом и затем суммирования этих чисел), scalaz также поддерживает это.

Это зависит от рассматриваемого класса, имеющего экземпляр Monoid, определенный для него (что на практике означает, что он должен иметь Zero и Semigroup). Моноид можно рассматривать как более слабое обобщение основной черты scala Numeric специально для суммирования; в конце концов, если вы можете определить нулевой элемент и способ добавить/объединить два элемента, тогда у вас есть все необходимое для получения суммы нескольких объектов.

Логика Scalaz точно такая же, как и вы суммируете целые числа вручную - list.foldLeft(0) { _ + _ } - за исключением того, что Zero предоставляет начальный нулевой элемент, а Semigroup обеспечивает реализацию + (называемый append).

Он может выглядеть примерно так:

import scalaz._
import Scalaz._

// Define Monoid for Blah
object Blah {
  implicit def zero4Blah: Zero[Blah] = zero(Blah("", 0))
  implicit def semigroup4Blah: Semigroup[Blah] = semigroup { (a, b) => 
    // Decide how to combine security names - just append them here
    Blah(a.security + b.security, a.price + b.price)
  }
}

// Now later in your class
val myList = List(Blah("a", 2.0), Blah("b", 4.0))
val mySum = myList.asMA.sum

В этом случае mySum будет фактически экземпляром Blah, равным Blah("ab", 6.0), а не просто Double.

ОК, для этого конкретного примера вы действительно не получаете столько, потому что получение "суммы" имен безопасности не очень полезно. Но для других классов (например, если у вас есть количество, а также цена или несколько соответствующих свойств), это может быть очень полезно. По большому счету, если вы можете определить способ добавления двух экземпляров вашего класса вместе, вы можете рассказать об этом скалаз (определив Semigroup); и если вы также можете определить нулевой элемент, вы можете использовать это определение, чтобы легко суммировать коллекции своего класса.