The standard modules std.range and std.algorithm provide a multitude of great functions that can be composed to express complex operations in a still readable way - based on ranges as building blocks.
The great thing with these algorithms is that you just have to define your own range and you will directly be able to profit from what already is in the standard library.
filter
- Given a lambda as the template parameter,
generate a new range that filters elements:
filter!(a => a > 20)(range);
map
- Generate a new range using the predicate
defined as a template parameter:
[1, 2, 3].map!(x => to!string(x));
each
- Poor man's foreach
as a range crunching
function:
[1, 2, 3].each!(a => writeln(a));
take
- Limit to N elements:
theBigBigRange.take(10);
zip
- iterates over two ranges
in parallel returning a tuple from both
ranges during iteration:
assert(zip([1,2], ["hello","world"]).front
== tuple(1, "hello"));
generate
- takes a function and creates a range
which in turn calls it on each iteration, for example:
alias RandomRange = generate!(() => uniform(1, 1000));
cycle
- returns a range that repeats the given input range
forever.
auto c = cycle([1]);
// range will never be empty!
assert(!c.empty);