разница между foldLeft и reduceLeft в Scala



я узнал основную разницу между foldLeft и reduceLeft



метод использовать-foldleft:




  • начальное значение должно быть вынесено


reduceLeft:




  • берет первый элемент коллекции в качестве начального значения

  • бросает исключение, если коллекция пуста


есть ли разница ?



любая конкретная причина иметь два метода с аналогичная функциональность?

783   7  

7 ответов:

несколько вещей, чтобы упомянуть здесь, прежде чем давать фактический ответ:

  • Ваш вопрос не имеет ничего общего с left, это скорее о разнице между уменьшением и складыванием
  • разница не в реализации, просто посмотрите на подписи.
  • вопрос не имеет ничего общего с Scala в частности, это скорее о двух концепциях функционального программирование.

возвращаясь к вашему вопросу:

вот подпись foldLeft (можно foldRight для точки я собираюсь сделать):

def foldLeft [B] (z: B)(f: (B, A) => B): B

а вот и подпись reduceLeft (опять же направление здесь не имеет значения)

def reduceLeft [B >: A] (f: (B, A) => B): B

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

когда вы называете reduceLeft на List[Int] он будет буквально сводят весь список целых чисел в одно значение, которое будет иметь тип Int (или супертипом Int, следовательно,[B >: A]).

когда вы называете foldLeft на List[Int] он сложит весь список (представьте себе, свернув лист бумаги) в одно значение, но это значение не должно быть даже связано с Int (отсюда [B]).

вот пример:

def listWithSum(numbers: List[Int]) = numbers.foldLeft((List[Int](), 0)) {
   (resultingTuple, currentInteger) =>
      (currentInteger :: resultingTuple._1, currentInteger + resultingTuple._2)
}

этот метод принимает List[Int] и возвращает a Tuple2[List[Int], Int] или (List[Int] -> Int). Он вычисляет сумму и возвращает кортеж со списком целых чисел и сумму. Кстати, список возвращается назад, потому что мы использовали foldLeft вместо foldRight.

reduceLeft это просто удобный метод. Это эквивалентно

list.tail.foldLeft(list.head)(_)

foldLeft является более общим, вы можете использовать его для производства чего-то совершенно другого, чем то, что вы изначально положили. Тогда как reduceLeft может привести только к конечному результату того же типа или супер типа типа коллекции. Например:

List(1,3,5).foldLeft(0) { _ + _ }
List(1,3,5).foldLeft(List[String]()) { (a, b) => b.toString :: a }

The foldLeft применит закрытие с последним сложенным результатом (первый раз с использованием начального значения) и следующим значением.

reduceLeft С другой стороны, сначала объединит два значения из списка и применит их к закрытие. Затем он объединит остальные значения с кумулятивным результатом. Смотрите:

List(1,3,5).reduceLeft { (a, b) => println("a " + a + ", b " + b); a + b }

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

Для справки:reduceLeft будет ошибка, если применяется к пустому контейнеру со следующей ошибкой.

java.lang.UnsupportedOperationException: empty.reduceLeft

переработка кода для использования

myList foldLeft(List[String]()) {(a,b) => a+b}

Это один из возможных вариантов. Другой-использовать reduceLeftOption вариант, который возвращает параметр обернутый результат.

myList reduceLeftOption {(a,b) => a+b} match {
  case None    => // handle no result as necessary
  case Some(v) => println(v)
}

основная причина, по которой они оба находятся в стандартной библиотеке Scala, вероятно, потому, что они оба находятся в стандартной библиотеке Haskell (называется foldl и foldl1). Если reduceLeft не было, это довольно часто будет определяться как метод удобства в разных проектах.

С принципы функционального программирования в Scala (Мартин Одерский):

функции reduceLeft определяется в терминах более общей функции, foldLeft.

foldLeft как reduceLeft но принимает аккумуляторz, как дополнительный параметр, который возвращается, когда foldLeft вызывается в пустом списке:

(List (x1, ..., xn) foldLeft z)(op) = (...(z op x1) op ...) op x

[в противоположность reduceLeft, который бросает исключение при вызове в пустом списке.]

курс (см. лекцию 5.5) содержит абстрактные определения этих функций, которые иллюстрируют их различия, хотя они очень похожи в использовании сопоставления шаблонов и рекурсии.

abstract class List[T] { ...
  def reduceLeft(op: (T,T)=>T) : T = this match{
    case Nil     => throw new Error("Nil.reduceLeft")
    case x :: xs => (xs foldLeft x)(op)
  }
  def foldLeft[U](z: U)(op: (U,T)=>U): U = this match{
    case Nil     => z
    case x :: xs => (xs foldLeft op(z, x))(op)
  }
}

отметим, что foldLeft возвращает значение типа U, который не обязательно того же типа, что и List[T], но reduceLeft возвращает значение того же типа, что и список).

чтобы действительно понять, что вы делаете с fold / reduce, проверьте это: http://wiki.tcl.tk/17983 очень хорошее объяснение. как только вы получите понятие складки, сокращение придет вместе с ответом выше: список.хвост.метод использовать-foldleft(список.голова) (_)

Comments

    Ничего не найдено.