scan

지연 평가되는 누적 연산 — reduce와 비슷하지만 마지막 값만이 아니라 중간 값을 모두 내보냅니다.

Iterable<B> scan<A, B>(B Function(B acc, A a) f, B seed, Iterable<A> iterable) Iterable<A> scan1<A>(A Function(A acc, A a) f, Iterable<A> iterable) FxAsyncIterable<B> scanAsync<A, B>(FutureOr<B> Function(B acc, A a) f, FutureOr<B> seed, FxAsyncIterable<A> iterable) FxAsyncIterable<A> scan1Async<A>(FutureOr<A> Function(A acc, A a) f, FxAsyncIterable<A> iterable) Fx<B> Fx.scan<B>(B Function(B acc, T a) f, B seed) // chain FxAsync<B> FxAsync.scan<B>(FutureOr<B> Function(B acc, T a) f, FutureOr<B> seed) FxEvents<R> FxEvents<T>.scan<R>(R Function(R acc, T a) f, R seed) // chain (events)

강의

scan은 중간 단계를 그대로 드러내는 reduce/fold입니다. 이터러블을 최종 값 하나로 접어 버리는 대신, 초깃값 자체를 첫 값으로 포함해 누적된 모든 중간 결과를 내보냅니다. 첫 값이 초깃값이라는 점이 중요합니다 — scan(f, 0, [1, 2, 3])은 세 개가 아니라 네 개의 값 (0, 그리고 누적 합 세 개)을 만들어 냅니다.

scan1은 초깃값이 없는 변형으로, FxTS의 scan(f, iterable) 오버로드(seed 인자가 없는 형태)를 옮겨 온 것입니다. 이터러블의 첫 원소를 초기 누적값으로 삼아 곧바로 내보낸 뒤 나머지를 계속 접어 나갑니다 — reducefold의 관계와 같습니다. 빈 이터러블에서는 scan1이 초깃값으로 삼을 첫 원소가 없으므로 아무것도 내보내지 않습니다. scan1에는 체인 메서드가 없다는 점에 유의하세요(Fx/FxAsync에는 scan만 있습니다). data-first 형태로 호출하세요: scan1(f, iterable).

둘 다 지연 평가됩니다. 값을 끌어당기기 전까지는 아무것도 실행되지 않습니다. 비동기 쪽에서는 scanAsync/scan1Async가 여전히 순서대로 한 단계씩 접어 나가므로(각 단계가 이전 결과를 필요로 하므로) .concurrent(n)이 폴드 자체를 병렬화하지는 못합니다. 다만 누적 함수 자체가 가볍기만 하다면 상류의 fetch 단계는 동시에 실행되게 할 수 있습니다. 데모 2를 참고하세요.

데모 1 · 기본 — scan과 scan1

데모 2 · 비동기, 그리고 상류의 동시성

폴드 자체는 순차적으로 남지만, 거기에 값을 공급하는 fetch는 그럴 필요가 없습니다.

직접 해 보기

연습: scan으로 0에서 시작하는 걸음 수의 누적 합계를 만들어 보세요.

관련 항목: reduce/fold — 최종 값 하나로 접기 · flat — 중첩된 이터러블 평탄화 · peek — 변환 없이 들여다보기 · concurrent — 병렬 평가