Scala-使用foldLeft有条件地对列表中的元素求和

时间:2018-11-05 23:08:48

标签: scala

我正在尝试解决我上课的初学者问题

class Invoice {
 var amount   = 0d
 var item   = ""
 var paid = false
 }

并给出发票清单,我需要使用foldLeft汇总未付金额并将其作为浮点数返回。我的尝试:

def toBePaid(as: List[Invoice]): Double = {
 var total = 0
 as.foldLeft(0.0)((as,total) => if (as.paid==false) total + as.amount)
 }

但是它不起作用。我在做什么错了?

好的,在给定的帮助下,它可以正常工作:

def toBePaid(as: List[Invoice]): Double = {
 as.foldLeft(0.0)((total,as) => if (as.paid==false) total + as.amount else total + 0)
 }

1 个答案:

答案 0 :(得分:1)

这里有一些简单的错误。首先,您在foldleft的迭代函数中将参数倒退。签名为foldLeft[B](z: B)(op: (B, A) ⇒ B): B,因此您的示例应为(total, as) => ...。您还将隐藏total变量,在toBePaid的主体中声明它,并在迭代函数中再次声明它,因此在total + as.amount中对total的引用是不明确的。

更大的问题是您正在混合可变状态和不可变状态。根据经验,Scala中的大多数构造都设计为仅在不可变状态下使用(val,而不是var)。在您的示例中,没有理由更改“发票”类的值,因此应将它们全部声明为val,而不是var。但这在这种特定情况下不如您计算总数的重要性重要。

toBePaid中,您像经典的命令式循环一样设置循环:通过创建一个初始化为0的可变变量,这样您就可以通过每次向其添加as.amount来改变该值。使用foldLeft,您无需跟踪函数外部的总和,折叠即可为您处理。折叠松散地说:“给定一个初始状态(0.0),一个方法接受一个状态/元素对并计算一个新状态,然后将最终状态返回给我。”您提供了一个函数,该函数利用元素(as)和状态(总计)来计算新状态。 Fold将采用新产生的状态并将其作为下一次迭代的状态。简而言之,您可以删除声明var total = 0

另一个问题是迭代函数必须返回一个新状态(即新的total)。在您的情况下,如果if语句为true,则返回下一个状态,但else情况无法返回任何内容。如果未支付发票,则需要让else ...返回下一个状态。另外,在调用foldLeft之前,您可以调用filter仅过滤已付款的发票,然后无条件调用foldLeft