Search code examples
scalafilterpattern-matchingfold

Scala: Problem with foldLeft with negative numbers in list


I am writing a Scala function that returns the sum of even elements in a list, minus sum of odd elements in a list. I cannot use mutables, recursion or for/while loops for my solution. The code below passes 2/3 tests, but I can't seem to figure out why it can't compute the last test correctly.

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

My code is outputting this:

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

I am extremely confused why these negative numbers are tripping up the rest of my code. I saw a post explaining the order of operations with foldLeft foldRight, but even changing to foldRight still yields i3: Int = -200. Is there a detail I'm missing? Any guidance / help would be greatly appreciated.


Solution

  • The problem isn't foldLeft or foldRight, the problem is the way you filter out odd values:

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

    Should be:

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

    The predicate _ % 2 == 1 will only yield true for positive elements. For example, the expression -15 % 2 is equal to -1, and not 1.

    As as side note, we can also make this a bit more efficient:

    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
    }
    

    Or even better by accumulating the difference only:

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