나는 기본적인 차이를 배운 사이 foldLeft
와reduceLeft
왼쪽 :
- 초기 값을 전달해야합니다
왼쪽 :
- 컬렉션의 첫 번째 요소를 초기 값으로 사용
- 컬렉션이 비어 있으면 예외가 발생합니다.
다른 차이점이 있습니까?
기능이 비슷한 두 가지 방법이 필요한 구체적인 이유가 있습니까?
답변
실제 답변을 제공하기 전에 몇 가지 언급 할 사항이 있습니다.
- 귀하의 질문은와 관련이 없으며
left
축소와 접기의 차이점에 관한 것입니다. - 차이점은 전혀 구현이 아니며 서명 만 살펴 보는 것입니다.
- 이 질문은 스칼라와 관련이 없으며 기능 프로그래밍의 두 가지 개념에 관한 것입니다.
질문으로 돌아 가기 :
여기에 서명이 있습니다 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
A의 말을 List[Int]
말 그대로 형식이 될 것입니다 단일 값으로 정수의 전체 목록을 줄일 수 있습니다 Int
(또는의 슈퍼 Int
따라서 [B >: A]
).
foldLeft
say 를 호출 List[Int]
하면 전체 목록 (종이 롤링 상상)을 단일 값으로 접을 수 있지만이 값은 Int
(따라서 [B]
) 관련이 없어도 됩니다.
예를 들면 다음과 같습니다.
def listWithSum(numbers: List[Int]) = numbers.foldLeft((List.empty[Int], 0)) {
(resultingTuple, currentInteger) =>
(currentInteger :: resultingTuple._1, currentInteger + resultingTuple._2)
}
이 방법은 소요 List[Int]
와 반환 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 }
는 foldLeft
최종 결과 절첩 폐쇄 (제 시간의 초기 값을 사용하여)하고, 다음 값을 적용한다.
reduceLeft
반면에 먼저 목록에서 두 값을 결합하여 클로저에 적용합니다. 다음으로 나머지 값을 누적 결과와 결합합니다. 보다:
List(1,3,5).reduceLeft { (a, b) => println("a " + a + ", b " + b); a + b }
목록이 비어 있으면 foldLeft
초기 값을 올바른 결과로 표시 할 수 있습니다. reduceLeft
반면에 목록에서 하나 이상의 값을 찾을 수없는 경우 유효한 값이 없습니다.
답변
이들이 Scala 표준 라이브러리에있는 기본 이유는 아마도 Haskell 표준 라이브러리 ( foldl
와 foldl1
) 에 있기 때문일 것입니다 . 그렇지 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)
}
답변
에서 스칼라 함수 프로그래밍 원칙 (마틴 오더 스키) :
이 기능
reduceLeft
은보다 일반적인 기능으로 정의됩니다foldLeft
.
foldLeft
는 빈 목록에서 호출 될 때 반환되는 추가 매개 변수로 accumulator를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
아주 좋은 설명을 확인하십시오 . 접기의 개념을 얻으면 reduce는 위의 답변과 함께 나타납니다 : list.tail.foldLeft (list.head) (_)