对对象列表求和的 Scala 语法是什么?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/7578287/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
What is the Scala syntax for summing a List of objects?
提问by deltanovember
For example
例如
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
What is the syntax for obtaining the sum?
获取总和的语法是什么?
回答by Tom Crockett
Try this:
试试这个:
val sum = myList.map(_.price).sum
Or alternately:
或者交替:
val sum = myList.foldLeft(0.0)(_ + _.price)
You appear to be trying to use this method:
您似乎正在尝试使用此方法:
def sum [B >: A] (implicit num: Numeric[B]): B
and the compiler can't figure out how the function you're providing is an instance of Numeric, because it isn't.
并且编译器无法弄清楚您提供的函数如何是 的实例Numeric,因为它不是。
回答by missingfaktor
Scalaz has this method under a name foldMap. The signature is:
Scalaz 在一个名字下有这个方法foldMap。签名是:
def M[A].foldMap[B](f: A => B)(implicit f: Foldable[M], m: Monoid[B]): B
Usage:
用法:
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
Bhere doesn't have to be a numeric type. It can be any monoid. Example:
B这里不必是数字类型。它可以是任何幺半群。例子:
scala> myList.foldMap(_.security)
res12: String = ab
回答by Andrzej Doyle
As an alternative to missingfaktor's Scalaz example, if you really want to sum a list of objects(as opposed to mapping each of them to a number and then summing those numbers), scalaz supports this as well.
作为 missingfaktor 的 Scalaz 示例的替代方案,如果您真的想对对象列表求和(而不是将它们中的每一个映射到一个数字然后对这些数字求和),scalaz 也支持这一点。
This depends on the class in question having an instance of Monoiddefined for it (which in practice means that it must have a Zeroand a Semigroupdefined). The monoid can be considered a weaker generalisation of core scala's Numerictrait specifically for summing; after all, if you can define a zero element and a way to add/combine two elements, then you have everything you need to get the sum of multiple objects.
这取决于所讨论的类是否为它定义了Monoid的实例(这实际上意味着它必须定义一个零和一个半群)。幺半群可以被认为是核心 scalaNumeric特性的较弱泛化,专门用于求和;毕竟,如果您可以定义一个零元素和一种添加/组合两个元素的方法,那么您就拥有了获取多个对象总和所需的一切。
Scalaz' logic is exactly the same as the way you'd sum integers manually - list.foldLeft(0) { _ + _ }- except that the Zeroprovides the initial zero element, and the Semigroupprovides the implementation of +(called append).
Scalaz 的逻辑与您手动对整数求和的方式完全相同list.foldLeft(0) { _ + _ }- 除了Zero提供初始零元素,并Semigroup提供+(称为append)的实现。
It might look something like this:
它可能看起来像这样:
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
In this case mySumwill actually be an instance of Blah equal to Blah("ab", 6.0), rather than just being a Double.
在这种情况下,mySum实际上是 Blah 的一个实例等于Blah("ab", 6.0),而不仅仅是一个 Double。
OK, for this particular example you don't really gain that much because getting a "sum" of the security names isn't very useful. But for other classes (e.g. if you had a quantity as well as a price, or multiple relevant properties) this can be very useful. Fundamentally it's great that if you can define some way of adding two instances of your class together, you can tell scalaz about it (by defining a Semigroup); and if you can define a zero element too, you can use that definition to easily sum collections of your class.
好吧,对于这个特定的例子,你并没有真正获得那么多,因为获得安全名称的“总和”并不是很有用。但是对于其他类(例如,如果您有数量和价格,或多个相关属性),这可能非常有用。从根本上说,如果您可以定义将类的两个实例添加在一起的某种方式,那么您可以告诉 scalaz(通过定义 a Semigroup);如果您也可以定义零元素,则可以使用该定义轻松地对类的集合进行求和。

