Подтвердить что ты не робот

Суммирование значений в списке

Я пытаюсь написать функцию scala, которая будет рекурсивно суммировать значения в списке. Вот что я до сих пор:

  def sum(xs: List[Int]): Int = {
    val num = List(xs.head)   
    if(!xs.isEmpty) {
      sum(xs.tail)
    }
    0
   }

Я не знаю, как суммировать отдельные значения Int как часть функции. Я рассматриваю возможность определения новой функции в сумме функции и использую локальную переменную, которая суммирует значения, как List isu itated. Но это похоже на императивный подход. Есть ли альтернативный метод?

4b9b3361

Ответ 1

Здесь "стандартный" рекурсивный подход:

def sum(xs: List[Int]): Int = {
  xs match {
    case x :: tail => x + sum(tail) // if there is an element, add it to the sum of the tail
    case Nil => 0 // if there are no elements, then the sum is 0
  }
}

И, здесь, функция хвоста-рекурсивная. Он будет более эффективен, чем функция, отличная от хвоста, поскольку компилятор превращает ее в цикл while, который не требует нажатия нового кадра в стеке для каждого рекурсивного вызова:

def sum(xs: List[Int]): Int = {
  @tailrec
  def inner(xs: List[Int], accum: Int): Int = {
    xs match {
      case x :: tail => inner(tail, accum + x)
      case Nil => accum
    }
  }
  inner(xs, 0)
}

Ответ 2

Также вы можете не использовать рекурсию напрямую и вместо этого использовать некоторые базовые абстракции:

val l = List(1, 3, 5, 11, -1, -3, -5)
l.foldLeft(0)(_ + _) // same as l.foldLeft(0)((a,b) => a + b)

foldLeft имеет значение reduce() в python. Также существует foldRight, который также известен как accumulate (например, в SICP).

Ответ 3

С рекурсией я часто считаю целесообразным подумать о том, как вы описываете процесс на английском языке, поскольку это часто переводится в код без особых усложнений. Так что...

"Как вычислить сумму списка целых чисел рекурсивно?"

"Ну, какая сумма списка, 3 :: restOfList?

" Что restOfList?

"Это может быть что угодно, вы не знаете. Но помните, мы рекурсивно - а разве у вас нет функции для вычисления суммы списка?"

"Ну ладно, тогда сумма будет 3 + sum(restOfList).

" Правильно. Но теперь ваша единственная проблема в том, что каждая сумма определяется в терминах другого вызова sum(), поэтому вы никогда не сможете получить фактическое значение. Вам понадобится какая-то база случай, когда все действительно достигнет, и что вы можете обеспечить значение для. "

" Хм, ты прав ". Думает...

" Ну, так как ваши списки становятся короче и короче, какой самый короткий список? "

" Пустой список? "

" Правильно! А какая сумма пустого списка int? "

" Zero - я получаю его сейчас, поэтому, суммируя его, сумма пустого списка равна нулю, а сумма любого другого списка - это его первый элемент, добавленный к сумме остальной части.

И действительно, код мог читать почти точно так же, как последнее предложение:

def sumList(xs: List[Int]) = {
    if (xs.isEmpty) 0
    else xs.head + sumList(xs.tail)
}

(Варианты соответствия шаблонов, такие как предложенные Ким Стебелем, по существу идентичны этому, они просто выражают условия более "функциональным" способом.)

Ответ 4

Вы не можете сделать это проще:

val list  = List(3, 4, 12);
println(list.sum); // result will be 19

Надеюсь, это поможет:)

Ответ 5

Ваш код хорош, но вам не нужно временное значение num. В Scala [If] - выражение и возвращает значение, это будет возвращено как значение функции sum. Поэтому ваш код будет реорганизован на:

def sum(xs: List[Int]): Int = {
    if(xs.isEmpty) 0
    else xs.head + sum(xs.tail)

}

Если список пуст, возвращаем 0, вы добавляете к главному номеру оставшуюся часть списка

Ответ 6

Каноническая реализация с сопоставлением с образцом:

def sum(xs:List[Int]) = xs match {
  case Nil => 0
  case x::xs => x + sum(xs)
}

Это не хвостовая рекурсия, но ее легко понять.

Ответ 7

В значительной степени основывается на ответе @Kim:

def sum(xs: List[Int]): Int = {
    if (xs.isEmpty) throw new IllegalArgumentException("Empty list provided for sum operation")
    def inner(xs: List[Int]): Int = {
      xs match {
        case Nil => 0
        case x :: tail => xs.head + inner(xs.tail)
      }
    }
    return inner(xs)
  }

Внутренняя функция рекурсивна, и когда предоставляется пустой список, вы получаете соответствующее исключение.

Ответ 8

 def sum(xs: List[Int]): Int = { 
  def loop(accum: Int, xs: List[Int]): Int = { 
    if (xs.isEmpty) accum
    else loop(accum + xs.head, xs.tail)
  }
  loop(0,xs)  
}

Ответ 9

Если вам требуется написать рекурсивную функцию с помощью isEmpty, head и tail, а также исключить исключение в случае аргумента пустого списка:

def sum(xs: List[Int]): Int = 
  if (xs.isEmpty) throw new IllegalArgumentException("sum of empty list") 
  else if (xs.tail.isEmpty) xs.head 
  else xs.head + sum(xs.tail)

Ответ 10

Чтобы добавить еще один возможный ответ на этот вопрос, вот решение, которое я придумал, это небольшая вариация ответа @jgaw и использует аннотацию @tailrec:

def sum(xs: List[Int]): Int = {
  if (xs.isEmpty) throw new Exception // May want to tailor this to either some sort of case class or do something else

  @tailrec
  def go(l: List[Int], acc: Int): Int = {
    if (l.tail == Nil) l.head + acc // If the current 'list' (current element in xs) does not have a tail (no more elements after), then we reached the end of the list.
    else go(l.tail, l.head + acc) // Iterate to the next, add on the current accumulation
  }

  go(xs, 0)
}

Быстрая заметка о проверке наличия пустого списка; при программировании функционально предпочтительнее не бросать никаких исключений и вместо этого возвращать что-то другое (другое значение, функция, класс case и т.д.), чтобы обрабатывать ошибки элегантно и продолжать протекать через программирование, а не останавливать его с помощью Exception. Я бросил один в примере выше, так как мы просто смотрим на рекурсивно суммирующиеся элементы в списке.

Ответ 11

def sum(xs: List[Int]): Int = xs.sum

scala> sum(List(1,3,7,5))
res1: Int = 16

scala> sum(List())
res2: Int = 0

Ответ 12

Пробовал следующий метод без использования подстановочного подхода

def sum(xs: List[Int]) = {

  val listSize = xs.size

  def loop(a:Int,b:Int):Int={

    if(a==0||xs.isEmpty)
      b
    else
      loop(a-1,xs(a-1)+b)
  }

  loop(listSize,0)
}