Scala中reduceLeft与reduceRight的概念疑问及实现求助
关于Scala reduceLeft与reduceRight的疑惑解答
一、执行逻辑的解惑
你对执行逻辑的判断是正确的:对列表[1,2,3]执行加法得到1 + sum(2,3),这确实是reduceRight的执行逻辑,而非reduceLeft。
两者的核心区别在于结合方向:
- reduceLeft是从左到右依次结合,先计算最左边的两个元素,再将结果与下一个元素运算。对于
[1,2,3]的加法,执行顺序是((1+2)+3),对应你说的sum(1,2)+3。 - reduceRight是从右到左结合,先计算最右边的子列表,再将头部元素与子列表的运算结果结合。对于
[1,2,3]的加法,执行顺序是(1+(2+3)),也就是你看到的1 + sum(2,3)。
因为加法满足交换律和结合律,所以两种方式结果相同,但如果换成不满足结合律的操作(比如减法),结果会完全不同:
List(1,2,3).reduceLeft(_ - _)→(1-2)-3 = -4List(1,2,3).reduceRight(_ - _)→1-(2-3) = 2
所以你遇到的课件标注错误的概率很高,你的判断没问题。
二、用case语句实现reduceLeft的指导
先看课件里用case实现reduceRight的典型写法(递归模式匹配):
def reduceRight[T](list: List[T])(op: (T, T) => T): T = list match { case head :: Nil => head case head :: tail => op(head, reduceRight(tail)(op)) }
reduceLeft的递归实现需要从左累积结果,直接用模式匹配的话,需要借助辅助函数维护累积值(每次拿当前累积结果和下一个元素运算),具体实现如下:
def reduceLeft[T](list: List[T])(op: (T, T) => T): T = { // 辅助递归函数:acc是当前累积值,remaining是剩余未处理的列表 def loop(acc: T, remaining: List[T]): T = remaining match { case Nil => acc // 剩余列表为空,返回累积值 case next :: tail => loop(op(acc, next), tail) // 更新累积值并继续递归 } list match { case Nil => throw new UnsupportedOperationException("reduceLeft cannot be called on empty list") case head :: tail => loop(head, tail) // 初始累积值为列表首元素,启动递归 } }
如果不想用辅助函数,也可以用模式匹配直接处理多元素场景(可读性稍弱):
def reduceLeft[T](list: List[T])(op: (T, T) => T): T = list match { case Nil => throw new UnsupportedOperationException("reduceLeft on empty list") case head :: Nil => head case head :: next :: tail => reduceLeft(op(head, next) :: tail)(op) }
测试减法场景验证:
val nums = List(1,2,3) reduceLeft(nums)(_ - _) // 输出-4,符合reduceLeft的预期
内容的提问来源于stack exchange,提问作者figs_and_nuts
相关产品推荐
相关产品推荐

