Template std.algorithm.iteration.reduce
Implements the homonym function (also known as accumulate
, compress
, inject
, or foldl
) present in various programming
languages of functional flavor. There is also fold
which does
the same thing but with the opposite parameter order.
The call reduce!(fun)(seed, range)
first assigns seed
to
an internal variable result
, also called the accumulator.
Then, for each element x
in range
, result = fun(result, x)
gets evaluated. Finally, result
is returned.
The one-argument version reduce!(fun)(range)
works similarly, but it uses the first element of the range as the
seed (the range must be non-empty).
template reduce(fun...)
;
Contained Functions
Name | Description |
---|---|
reduce | No-seed version. The first element of r is used as the seed's value.
|
reduce | Seed version. The seed should be a single value if fun is a
single function. If fun is multiple functions, then seed
should be a Tuple , with one field per function in f .
|
Returns
the accumulated result
Parameters
Name | Description |
---|---|
fun | one or more functions |
See Also
fold
is functionally equivalent to reduce
with the argument
order reversed, and without the need to use tuple
for multiple seeds. This makes it easier to use in UFCS chains.
sum
is similar to reduce!((a, b) => a + b)
that offers
pairwise summing of floating point numbers.
Example
Many aggregate range operations turn out to be solved with reduce
quickly and easily. The example below illustrates reduce
's
remarkable power and flexibility.
import std .algorithm .comparison : max, min;
import std .math .operations : isClose;
import std .range;
int[] arr = [ 1, 2, 3, 4, 5 ];
// Sum all elements
auto sum = reduce!((a,b) => a + b)(0, arr);
writeln(sum); // 15
// Sum again, using a string predicate with "a" and "b"
sum = reduce!"a + b"(0, arr);
writeln(sum); // 15
// Compute the maximum of all elements
auto largest = reduce!(max)(arr);
writeln(largest); // 5
// Max again, but with Uniform Function Call Syntax (UFCS)
largest = arr .reduce!(max);
writeln(largest); // 5
// Compute the number of odd elements
auto odds = reduce!((a,b) => a + (b & 1))(0, arr);
writeln(odds); // 3
// Compute the sum of squares
auto ssquares = reduce!((a,b) => a + b * b)(0, arr);
writeln(ssquares); // 55
// Chain multiple ranges into seed
int[] a = [ 3, 4 ];
int[] b = [ 100 ];
auto r = reduce!("a + b")(chain(a, b));
writeln(r); // 107
// Mixing convertible types is fair game, too
double[] c = [ 2.5, 3.0 ];
auto r1 = reduce!("a + b")(chain(a, b, c));
assert(isClose(r1, 112.5));
// To minimize nesting of parentheses, Uniform Function Call Syntax can be used
auto r2 = chain(a, b, c) .reduce!("a + b");
assert(isClose(r2, 112.5));
Example
Sometimes it is very useful to compute multiple aggregates in one pass.
One advantage is that the computation is faster because the looping overhead
is shared. That's why reduce
accepts multiple functions.
If two or more functions are passed, reduce
returns a
Tuple
object with one member per passed-in function.
The number of seeds must be correspondingly increased.
import std .algorithm .comparison : max, min;
import std .math .operations : isClose;
import std .math .algebraic : sqrt;
import std .typecons : tuple, Tuple;
double[] a = [ 3.0, 4, 7, 11, 3, 2, 5 ];
// Compute minimum and maximum in one pass
auto r = reduce!(min, max)(a);
// The type of r is Tuple!(int, int)
assert(isClose(r[0], 2)); // minimum
assert(isClose(r[1], 11)); // maximum
// Compute sum and sum of squares in one pass
r = reduce!("a + b", "a + b * b")(tuple(0.0, 0.0), a);
assert(isClose(r[0], 35)); // sum
assert(isClose(r[1], 233)); // sum of squares
// Compute average and standard deviation from the above
auto avg = r[0] / a .length;
writeln(avg); // 5
auto stdev = sqrt(r[1] / a .length - avg * avg);
writeln(cast(int)stdev); // 2