Scala: проблема с foldLeft с отрицательными числами в списке - PullRequest
0 голосов
/ 19 февраля 2019

Я пишу функцию 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 голосов
/ 19 февраля 2019

Проблема в условии фильтра, который вы применяете в списке, чтобы найти нечетные числа.странное условие, что вы не работаете для отрицательного нечетного числа, потому что мод 2 возвращает -1 для этого вида числа.

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

, поэтому, если вы измените условия фильтра, все будет работать как положено.

Еще одно предложение: почему вы хотите использовать функцию складывания для простой операции суммирования, когда вы можете напрямую использовать функции суммирования?

  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 наFunciton

0 голосов
/ 19 февраля 2019

Проблема не в foldLeft или foldRight, проблема в том, как вы отфильтровываете нечетные значения:

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)
  }
}
...