Scala:foldLeft的问题在列表中为负数

时间:2019-02-19 12:59:50

标签: scala filter pattern-matching fold

我正在编写一个Scala函数,该函数返回列表中偶数元素的总和,减去列表中奇数元素的总和。我不能为我的解决方案使用可变,递归或for / while循环。下面的代码通过了2/3个测试,但是我似乎无法弄清为什么它不能正确计算上一个测试。

def sumOfEvenMinusOdd(l: List[Int]) : Int = {
    if (l.length == 0) return 0
    val evens = l.filter(_%2==0)
    val odds = l.filter(_%2==1)
    val evenSum = evens.foldLeft(0)(_+_)
    val oddSum = odds.foldLeft(0)(_+_)
    evenSum-oddSum
  }

//BEGIN TESTS
val i1 = sumOfEvenMinusOdd(List(1,3,5,4,5,2,1,0)) //answer: -9
val i2 = sumOfEvenMinusOdd(List(2,4,5,6,7,8,10)) //answer: 18
val i3 = sumOfEvenMinusOdd(List(109, 19, 12, 1, -5, -120, -15, 30,-33,-13, 12, 19, 3, 18, 1, -1)) //answer -133

我的代码输出如下:

defined function sumOfEvenMinusOdd
i1: Int = -9
i2: Int = 18
i3: Int = -200

我非常困惑为什么这些负数会破坏我的其余代码。我看到一个帖子解释了foldLeft foldRight的操作顺序,但是即使更改为foldRight仍然会产生i3:Int = -200。我缺少细节吗?任何指导/帮助将不胜感激。

2 个答案:

答案 0 :(得分:6)

问题不是foldLeftfoldRight,问题在于您过滤掉奇数值的方式:

val odds = l.filter(_ % 2 == 1)

应该是:

val odds = l.filter(_ % 2 != 0)

谓词_ % 2 == 1仅对肯定元素产生true。例如,表达式-15 % 2等于-1,而不是1

作为旁注,我们还可以使其更加有效:

def sumOfEvenMinusOdd(l: List[Int]): Int = {
  val (evenSum, oddSum) = l.foldLeft((0, 0)) {
    case ((even, odd), element) =>
      if (element % 2 == 0) (even + element, odd) else (even, odd + element)
  }
  evenSum - oddSum
}

或者通过仅累加差异甚至更好:

def sumOfEvenMinusOdd(l: List[Int]): Int = {
  l.foldLeft(0) {
    case (diff, element) =>
      diff + element * (if (element % 2 == 0) 1 else -1)
  }
}

答案 1 :(得分:0)

问题出在您应用列表以查找奇数的过滤条件上。 您对负奇数不起作用的奇数条件,因为mod 2对该数字返回-1。

number % 2 == 0 if number is even
number % 2 != 0 if number is odd

因此,如果您更改过滤条件,则所有功能都会按预期运行。

另一个建议: 当可以直接使用求和函数时,为什么要使用foldleft函数进行简单的求和运算?

  test("Test sum Of even minus odd") {
    def sumOfEvenMinusOdd(l: List[Int]) : Int = {
      val evensSum = l.filter(_%2 == 0).sum
      val oddsSum = l.filter(_%2 != 0).sum
      evensSum-oddsSum
    }

    assert(sumOfEvenMinusOdd(List.empty[Int]) == 0)
    assert(sumOfEvenMinusOdd(List(1,3,5,4,5,2,1,0)) == -9) //answer: -9
    assert(sumOfEvenMinusOdd(List(2,4,5,6,7,8,10)) == 18) //answer: 18
    assert(sumOfEvenMinusOdd(List(109, 19, 12, 1, -5, -120, -15, 30,-33,-13, 12, 19, 3, 18, 1, -1)) == -133)
  }

使用此解决方案,您的功能更加清晰,可以删除函数上的if