什么是用于求和对象列表的Scala语法?

del*_*ber 21 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
Run Code Online (Sandbox Code Playgroud)

获得总和的语法是什么?

Tom*_*ett 63

试试这个:

val sum = myList.map(_.price).sum
Run Code Online (Sandbox Code Playgroud)

或者:

val sum = myList.foldLeft(0.0)(_ + _.price)
Run Code Online (Sandbox Code Playgroud)

您似乎正在尝试使用此方法:

def sum [B >: A] (implicit num: Numeric[B]): B
Run Code Online (Sandbox Code Playgroud)

并且编译器无法弄清楚您提供的函数是如何实例的Numeric,因为它不是.


mis*_*tor 16

Scalaz在名称下使用此方法foldMap.签名是:

def M[A].foldMap[B](f: A => B)(implicit f: Foldable[M], m: Monoid[B]): B
Run Code Online (Sandbox Code Playgroud)

用法:

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
Run Code Online (Sandbox Code Playgroud)

B这里不必是数字类型.它可以是任何幺半群.例:

scala> myList.foldMap(_.security)
res12: String = ab
Run Code Online (Sandbox Code Playgroud)

  • +1我认为scalaz会有一些巫术,这使得这个超简洁;) (2认同)

And*_*yle 5

作为missingfaktor的Scalaz示例的替代方案,如果您真的想要对对象列表求和(而不是将每个对象映射到一个数字然后对这些数字求和),scalaz也支持这一点.

这取决于所讨论的类具有为其定义的Monoid实例(实际上它意味着它必须定义半群).幺半群可以被认为是核心斯卡拉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
Run Code Online (Sandbox Code Playgroud)

在这种情况下,mySum实际上将是Blah等于的实例Blah("ab", 6.0),而不仅仅是Double.

好的,对于这个特殊的例子,你并没有真正获得那么多,因为获得安全名称的"总和"并不是很有用.但对于其他类(例如,如果您有数量和价格,或多个相关属性),这可能非常有用.从根本上说,如果你可以定义一些将类的两个实例添加到一起的方法,那么你可以告诉scalaz它(通过定义一个Semigroup); 如果您也可以定义零元素,则可以使用该定义轻松地对类的集合求和.