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


196

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

왼쪽 :

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

왼쪽 :

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

다른 차이점이 있습니까?

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



질문을 "스칼라에서 접기와 축소의 차이"로 편집하면 좋을 것입니다.
페드 람 바 시리

답변:


302

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

  • 귀하의 질문은와 관련이 없으며 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.

시계 하나는 그들 모두를 지배 접어 깊이 설명에서 더 많은 것을 위해.


B슈퍼 타입 이 설명 이 A됩니까? 같은 것 B사실의 하위 유형이어야한다 A,하지 슈퍼. 예를 들어, s Banana <: Fruit <: Food의 목록이 있으면 Fruits를 포함하고있는 것으로 보이지만 Bananas 가 포함되어 있으면 Food유형이 Food맞습니까? 따라서이 경우 B수퍼 타입이 A이고 Bs 및 As 를 모두 포함 하는 목록이있는 경우 목록이 B아닌 유형이어야합니다 A. 이 불일치를 설명 할 수 있습니까?
socom1880

귀하의 질문을 올바르게 이해하고 있는지 잘 모르겠습니다. 내 5 살짜리 대답은 축소 기능에 대해 말하는 List[Banana]것이 단일 Banana또는 단일 Fruit또는 단일로 축소 될 수 있다는 것 Food입니다. 때문에 Fruit :> Banana와`음식 :> 바나나 '.
agilesteel

네 ... 실제로 감사합니다. 원래는 "유형 목록에 " Banana가 포함되어있을 수 있습니다. Fruit" 로 해석 되어 이해가되지 않습니다. 당신의 설명은 의미가 있습니다- f전달 되는 함수는 reduce()a Fruit또는 a를 초래할 수 있습니다 Food. 이는 B서명에서 서브 클래스가 아닌 수퍼 클래스 여야 함을 의미 합니다.
socom1880

193

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

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

11
좋은, 간결한 답변 :) reducelft그래도 철자를 수정하고 싶을 수도 있습니다
Hanxue

10
좋은 대답입니다. 이것은 왜 fold빈 목록에서 작동하지만 reduce그렇지 않은 이유를 강조 합니다 .
Mansoor Siddiqui

44

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


5

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


5

참고 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)
}

2

에서 스칼라 함수 프로그래밍 원칙 (마틴 오더 스키) :

이 기능 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리스트와 동일한 유형)의 값을 반환합니다.


0

fold / reduce로 무엇을하고 있는지 이해하려면 http://wiki.tcl.tk/17983 아주 좋은 설명을 확인하십시오 . 접기의 개념을 얻으면 reduce는 위의 답변과 함께 나타납니다 : list.tail.foldLeft (list.head) (_)

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.