it-swarm.dev

Scala에서 foldLeft와 reduceLeft의 차이점

foldLeftreduceLeft의 기본적인 차이점을 배웠습니다.

foldLeft :

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

reduceLeft :

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

다른 차이점이 있습니까?

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

184
Rajesh Pitty

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

  • 귀하의 질문은 left과 관련이 없으며 축소와 접기의 차이점에 관한 것입니다.
  • 차이점은 전혀 구현이 아니며 서명 만 살펴보십시오.
  • 이 질문은 특히 Scala와 관련이 없으며 함수 프로그래밍의 두 가지 개념에 관한 것입니다.

귀하의 질문으로 돌아 가기 :

다음은 foldLeft의 시그니처입니다 (이 시점에서 foldRight 일 수도 있음).

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

그리고 여기 reduceLeft의 서명이 있습니다 (여기에서 방향은 중요하지 않습니다)

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

이 두 가지는 매우 비슷해 보이므로 혼동을 일으켰습니다. reduceLeftfoldLeft의 특별한 경우입니다 (그런데 때때로 는 둘 중 하나를 사용하여 동일한 것을 표현할 수 있음을 의미합니다).

List[Int]에서 reduceLeft say를 호출하면 문자 그대로 전체 정수 목록을 단일 값으로 줄이며, 이는 Int 유형 (또는 Int의 수퍼 유형이므로 [B >: A])이됩니다.

List[Int]에서 foldLeft say을 (를) 호출하면 전체 목록 (종이 롤링 상상)을 단일 값으로 접을 수 있지만이 값은 Int과 관련이 없어도됩니다 (따라서 [B]).

예를 들면 다음과 같습니다.

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

이 메소드는 List[Int]를 사용하고 Tuple2[List[Int], Int] 또는 (List[Int] -> Int)을 리턴합니다. 합계를 계산하고 정수 목록과 함께 합계를 반환하는 튜플을 반환합니다. 그런데 foldLeft 대신 foldRight을 사용했기 때문에 목록이 뒤로 반환됩니다.

보다 자세한 설명은 하나의 폴드를 모두 다룰 것 를보십시오.

287
agilesteel

reduceLeft은 편리한 방법입니다. 그것은

list.tail.foldLeft(list.head)(_)
184
Kim Stebel

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은 (는) 목록에서 하나 이상의 값을 찾을 수없는 경우 유효한 값을 갖지 않습니다.

43
thoredge

참고로 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)
}
5
Martin Smith

이들이 Scala 표준 라이브러리에있는 기본 이유는 아마도 Haskell 표준 라이브러리 (foldlfoldl1)에 있기 때문입니다. reduceLeft이 아닌 경우 다른 프로젝트에서 편의 방법으로 정의되는 경우가 많습니다.

5
Alexey Romanov

스칼라의 기능 프로그래밍 원칙 (Martin Odersky)에서 :

reduceLeft 함수는보다 일반적인 함수 foldLeft로 정의됩니다.

foldLeftreduceLeft과 비슷하지만 누산기 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)
  }
}

foldLeftU 유형의 값을 리턴하며, 반드시 List[T]와 동일한 유형은 아니지만 reduceLeft는 목록과 동일한 유형의 값을 리턴합니다).

2
C8H10N4O2

접기/축소 작업을 실제로 이해하려면 다음을 확인하십시오. http://wiki.tcl.tk/1798 아주 좋은 설명. 접기의 개념을 얻으면 reduce는 위의 답변과 함께 나타납니다 : list.tail.foldLeft (list.head) (_)

0
Henry H.