разница между foldLeft и reduceLeft в Scala
я узнал основную разницу между foldLeft и reduceLeft
метод использовать-foldleft:
- начальное значение должно быть вынесено
reduceLeft:
- берет первый элемент коллекции в качестве начального значения
- бросает исключение, если коллекция пуста
есть ли разница ?
любая конкретная причина иметь два метода с аналогичная функциональность?
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]и возвращает aTuple2[List[Int], Int]или(List[Int] -> Int). Он вычисляет сумму и возвращает кортеж со списком целых чисел и сумму. Кстати, список возвращается назад, потому что мы использовалиfoldLeftвместоfoldRight.
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