SCAN (Values, ItemProcessor, InitialValue) SCAN (Values; ItemProcessor; InitialValue)

Values

The array of values to scan.

ItemProcessor

A formula which is invoked once for every given value. To do its work, it has access to four parameters: Accumulator holds the current value of the accumulator, Value holds the current element of the array being processed and Index holds the current one-based index of the element of the array being processed. (If Index is 1, that means that the first value provided to this function is being processed.) Finally, Source is a reference to the array given as the first parameter to this function.

If an initial accumulator is not given, this formula is not invoked for the first given value, which instead serves as the initial accumulator.

InitialValue

The initial value of the accumulator. If it is not given, the first given value is used, and is returned as the first element of the resulting array.

Returns

An array holding every value taken on by the accumulator, holding as many elements as the given array.

Reduces an array of values using a user-supplied formula, returning every intermediate value of the accumulator.

SCAN does exactly what REDUCE does, but where REDUCE returns only the final value of the accumulator, SCAN returns all of them. SCAN ({ 1, 2, 3 }, Accumulator + Value) SCAN ({ 1; 2; 3 }; Accumulator + Value) returns { 1, 3, 6 }{ 1; 3; 6 }, the running total of the given array, whereas REDUCE ({ 1, 2, 3 }, Accumulator + Value) REDUCE ({ 1; 2; 3 }; Accumulator + Value) returns only 6.

The returned array always holds as many elements as the given array, and its last element is always the value the corresponding REDUCE formula would return.

Calculating a running total

A running total is the most common use of SCAN. Given an array of deposits and withdrawals, this formula returns the balance after each one:

SCAN ({ 100, - 30, 50 }, Accumulator + Value)
SCAN ({ 100; - 30; 50 }; Accumulator + Value)

The result is { 100, 70, 120 }{ 100; 70; 120 }. The first element is the first given value, 100, which serves as the initial accumulator. The second element is that accumulator plus the second given value, -30, giving 70. The third element is 70 plus 50, giving 120.

Setting the initial accumulator

The third parameter, if given, sets the initial value of the accumulator. The item processor is then invoked for every given value, including the first one:

SCAN ({ 1, 2, 3 }, Accumulator + Value, 10)
SCAN ({ 1; 2; 3 }; Accumulator + Value; 10)

The result is { 11, 13, 16 }{ 11; 13; 16 }. The initial accumulator itself is not part of the result, which is why the returned array holds three elements and not four.

Setting the initial accumulator also enables the accumulator to be something other than what the given array holds. This formula builds up a text string from an array of numbers, returning { "1", "1, 2", "1, 2, 3" }{ "1"; "1, 2"; "1, 2, 3" }:

SCAN ({ 1, 2, 3 }, IF (Index = 1, TOTEXT (Value), Accumulator & ", " & TOTEXT (Value)), "")
SCAN ({ 1; 2; 3 }; IF (Index = 1; TOTEXT (Value); Accumulator & ", " & TOTEXT (Value)); "")

SCAN, REDUCE and MAP

Use REDUCE when only the final value is of interest, such as when adding all the elements of an array together.

Use MAP when every element is transformed on its own, without an accumulator. MAP ({ 1, 2, 3 }, Element * 2) MAP ({ 1; 2; 3 }; Element * 2) returns { 2, 4, 6 }{ 2; 4; 6 }, and no element depends on any other. Only reach for SCAN when each element depends on the ones before it.

SCAN can be replicated with REDUCE, by setting the initial accumulator to an array and appending to it with | at every step, as described in the documentation of REDUCE. SCAN should be preferred. With REDUCE, you have to build the array yourself: start with an array as the accumulator, add an element to it for every value, and look up the previous element whenever you need it. With SCAN, you write only the calculation itself and the array is built for you. SCAN is also faster.

Examples

SCAN ({ 1, 2, 3 }, Accumulator + Value)
SCAN ({ 1; 2; 3 }; Accumulator + Value)

Returns the array { 1, 3, 6 }{ 1; 3; 6 }, the running total of the given array.

SCAN ({ 100, - 30, 50 }, Accumulator + Value)
SCAN ({ 100; - 30; 50 }; Accumulator + Value)

Returns the array { 100, 70, 120 }{ 100; 70; 120 }.

SCAN ({ 1, 2, 3 }, Accumulator + Value, 10)
SCAN ({ 1; 2; 3 }; Accumulator + Value; 10)

Returns the array { 11, 13, 16 }{ 11; 13; 16 }. The initial accumulator, 10, is not part of the result.

SCAN ({ 1, 5, 2, 8 }, MAX (Accumulator, Value))
SCAN ({ 1; 5; 2; 8 }; MAX (Accumulator; Value))

Returns the array { 1, 5, 5, 8 }{ 1; 5; 5; 8 }, the largest value seen so far at every position.

fxEngine Shell Want this in your own terminal? A standalone version is coming. Get notified.
Loading fxEngine Shell