[scala] 스칼라에서 foldLeft와 reduceLeft의 차이점

나는 기본적인 차이를 배운 사이 foldLeftreduceLeft

왼쪽 :

  • 초기 값을 전달해야합니다

왼쪽 :

  • 컬렉션의 첫 번째 요소를 초기 값으로 사용
  • 컬렉션이 비어 있으면 예외가 발생합니다.

다른 차이점이 있습니까?

기능이 비슷한 두 가지 방법이 필요한 구체적인 이유가 있습니까?



답변

실제 답변을 제공하기 전에 몇 가지 언급 할 사항이 있습니다.

  • 귀하의 질문은와 관련이 없으며 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(방식에 의해 당신이 것을 때때로 그들 중 하나를 사용하여 같은 일을 표현할 수는).

당신이 호출 할 때 reduceLeftA의 말을 List[Int]말 그대로 형식이 될 것입니다 단일 값으로 정수의 전체 목록을 줄일 수 있습니다 Int(또는의 슈퍼 Int따라서 [B >: A]).

foldLeftsay 를 호출 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 표준 라이브러리 ( foldlfoldl1) 에 있기 때문일 것입니다 . 그렇지 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 취 합니다. zfoldLeft

(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) (_)