我试图理解Scala中的聚合,并举一个例子,我理解逻辑,但第二个的结果我试图让我困惑。
请告诉我,我哪里出错了。
代码:
val list1 = List("This", "is", "an", "example");
val b = list1.aggregate(1)(_ * _.length(), _ * _)
1 *“This”。length = 4
1 *“is”。length = 2
1 *“an”。length = 2
1 *“example”.length = 7
4 * 2 = 8,2 * 7 = 14
8 * 14 = 112
输出也是112。 但对于下面的内容,
val c = list1.aggregate(1)(_ * _.length(), _ + _)
我以为会是这样的。 4,2,2,7
4 + 2 = 6
2 + 7 = 9
6 + 9 = 15,
但输出仍为112。
理想情况下,我在seqop
提到的操作,_ * _.length
请你解释或纠正我哪里出错了。?
答案 0 :(得分:0)
aggregate
应该用于仅计算关联和交换操作。让我们看看函数的签名:
def aggregate[B](z: ⇒ B)(seqop: (B, A) ⇒ B, combop: (B, B) ⇒ B): B
B
可以看作是累加器(并且将是您的输出)。你给出一个初始输出值,然后第一个函数是如何向这个累加器添加一个值A
,第二个函数是如何合并2个累加器。 Scala"选择"聚合您的集合的方法,但如果您的聚合不是关联和可交换的,则输出不是确定性的,因为订单很重要。看看这个例子:
val l = List(1, 2, 3, 4)
l.aggregate(0)(_ + _, _ * _)
如果我们创建一个累加器,然后汇总我们获得的所有值1 + 2 + 3 + 4 = 10
,但如果我们决定通过将列表分成两半来并行化,那么我们就可以(1 + 2) * (3 + 4) = 21
。
所以现在发生的事情是,List
聚合与foldLeft
相同,这解释了为什么更改第二个函数并没有改变输出。但aggregate
可能有用的地方就是Spark或其他分布式环境,在这些环境中,独立地对每个分区进行折叠可能很有用,然后将结果与第二个函数结合起来。