Report a bug
If you spot a problem with this page, click here to create a Bugzilla issue.
Improve this page
Quickly fork, edit online, and submit a pull request for this page.
Requires a signed-in GitHub account. This works well for small changes.
If you'd like to make larger changes you may want to consider using
a local clone.
std.algorithm.iteration
This is a submodule of std.algorithm.
It contains generic iteration algorithms.
Function Name | Description |
---|---|
cache | Eagerly evaluates and caches another range's front. |
cacheBidirectional | As above, but also provides back and popBack. |
chunkBy | chunkBy!((a,b) => a[1] == b[1])([[1, 1], [1, 2], [2, 2], [2, 1]]) returns a range containing 3 subranges: the first with just [1, 1]; the second with the elements [1, 2] and [2, 2]; and the third with just [2, 1]. |
cumulativeFold | cumulativeFold!((a, b) => a + b)([1, 2, 3, 4]) returns a lazily-evaluated range containing the successive reduced values 1, 3, 6, 10. |
each | each!writeln([1, 2, 3]) eagerly prints the numbers 1, 2 and 3 on their own lines. |
filter | filter!(a => a > 0)([1, -1, 2, 0, -3]) iterates over elements 1 and 2. |
filterBidirectional | Similar to filter, but also provides back and popBack at a small increase in cost. |
fold | fold!((a, b) => a + b)([1, 2, 3, 4]) returns 10. |
group | group([5, 2, 2, 3, 3]) returns a range containing the tuples tuple(5, 1), tuple(2, 2), and tuple(3, 2). |
joiner | joiner(["hello", "world!"], "; ") returns a range that iterates over the characters "hello; world!". No new string is created - the existing inputs are iterated. |
map | map!(a => a * 2)([1, 2, 3]) lazily returns a range with the numbers 2, 4, 6. |
permutations | Lazily computes all permutations using Heap's algorithm. |
reduce | reduce!((a, b) => a + b)([1, 2, 3, 4]) returns 10. This is the old implementation of fold. |
splitter | Lazily splits a range by a separator. |
sum | Same as fold, but specialized for accurate summation. |
uniq | Iterates over the unique elements in a range, which is assumed sorted. |
License:
Authors:
Source: std/algorithm/iteration.d
- auto
cache
(Range)(Rangerange
)
if (isInputRange!Range);
autocacheBidirectional
(Range)(Rangerange
)
if (isBidirectionalRange!Range); cache
eagerly evaluates front ofrange
on each construction or call to popFront, to store the result in acache
. The result is then directly returned when front is called, rather than re-evaluated.This can be a useful function to place in a chain, after functions that have expensive evaluation, as a lazy alternative to std.array.array. In particular, it can be placed after a call to map, or before a call to filter.cache
may provide bidirectional iteration if needed, but since this comes at an increased cost, it must be explicitly requested via the call tocacheBidirectional
. Furthermore, a bidirectionalcache
will evaluate the "center" element twice, when there is only one element left in therange
.cache
does not provide random access primitives, ascache
would be unable tocache
the random accesses. If Range provides slicing primitives, thencache
will provide the same slicing primitives, but hasSlicing!Cache will not yieldtrue
(as the std.range.primitives.hasSlicing trait also checks for random access).Parameters:Range range
an input range
Returns:an inputrange
with the cached values ofrange
Examples:import std.algorithm.comparison : equal; import std.stdio, std.range; import std.typecons : tuple; ulong counter = 0; double fun(int x) { ++counter; // http://en.wikipedia.org/wiki/Quartic_function return ( (x + 4.0) * (x + 1.0) * (x - 1.0) * (x - 3.0) ) / 14.0 + 0.5; } // Without cache, with array (greedy) auto result1 = iota(-4, 5).map!(a =>tuple(a, fun(a)))() .filter!(a => a[1] < 0)() .map!(a => a[0])() .array(); // the values of x that have a negative y are: assert(equal(result1, [-3, -2, 2])); // Check how many times fun was evaluated. // As many times as the number of items in both source and result. assert(counter == iota(-4, 5).length + result1.length); counter = 0; // Without array, with cache (lazy) auto result2 = iota(-4, 5).map!(a =>tuple(a, fun(a)))() .cache() .filter!(a => a[1] < 0)() .map!(a => a[0])(); // the values of x that have a negative y are: assert(equal(result2, [-3, -2, 2])); // Check how many times fun was evaluated. // Only as many times as the number of items in source. assert(counter == iota(-4, 5).length);
Examples:Tip:cache
is eager when evaluating elements. If calling front on the underlying range has a side effect, it will be observeable before calling front on the actual cached range. Furthermore, care should be taken composingcache
with std.range.take. By placing take beforecache
, thencache
will be "aware" of when the range ends, and correctly stop caching elements when needed. If calling front has no side effect though, placing take aftercache
may yield a faster range. Either way, the resulting ranges will be equivalent, but maybe not at the same cost or side effects.import std.algorithm.comparison : equal; import std.range; int i = 0; auto r = iota(0, 4).tee!((a){i = a;}, No.pipeOnPop); auto r1 = r.take(3).cache(); auto r2 = r.cache().take(3); assert(equal(r1, [0, 1, 2])); assert(i == 2); //The last "seen" element was 2. The data in cache has been cleared. assert(equal(r2, [0, 1, 2])); assert(i == 3); //cache has accessed 3. It is still stored internally by cache.
- template
map
(fun...) if (fun.length >= 1) - auto
map
(Range)(Range r) if (isInputRange!(Unqual!Range));Implements the homonym function (also known as transform) present in many languages of functional flavor. The callmap
!(fun)(range) returns a range of which elements are obtained by applying fun(a) left to right for all elements a in range. The original ranges are not changed. Evaluation is done lazily.Parameters:fun one or more functions Range r an input range Returns:a range with each fun applied to all the elements. If there is more than one fun, the element type will be Tuple containing one element for each fun.See Also:Examples:import std.algorithm.comparison : equal; import std.range : chain; int[] arr1 = [ 1, 2, 3, 4 ]; int[] arr2 = [ 5, 6 ]; auto squares = map!(a => a * a)(chain(arr1, arr2)); assert(equal(squares, [ 1, 4, 9, 16, 25, 36 ]));
Examples:Multiple functions can be passed tomap
. In that case, the element type ofmap
is a tuple containing one element for each function.auto sums = [2, 4, 6, 8]; auto products = [1, 4, 9, 16]; size_t i = 0; foreach (result; [ 1, 2, 3, 4 ].map!("a + a", "a * a")) { assert(result[0] == sums[i]); assert(result[1] == products[i]); ++i; }
Examples:You may aliasmap
with some function(s) to a symbol and use it separately:import std.algorithm.comparison : equal; import std.conv : to; alias stringize = map!(to!string); assert(equal(stringize([ 1, 2, 3, 4 ]), [ "1", "2", "3", "4" ]));
- template
each
(alias pred = "a") - Eagerly iterates over r and calls pred over each element.If no predicate is specified,
each
will default to doing nothing but consuming the entire range. .front will be evaluated, but this can be avoided by explicitly specifying a predicate lambda with a lazy parameter.each
also supports opApply-based iterators, so it will work with e.g. std.parallelism.parallel.Parameters:pred predicate to apply to each
element of the rangeRange r range or iterable over which each
iteratesSee Also:Examples:import std.range : iota; long[] arr; iota(5).each!(n => arr ~= n); assert(arr == [0, 1, 2, 3, 4]); // If the range supports it, the value can be mutated in place arr.each!((ref n) => n++); assert(arr == [1, 2, 3, 4, 5]); arr.each!"a++"; assert(arr == [2, 3, 4, 5, 6]); // by-ref lambdas are not allowed for non-ref ranges static assert(!is(typeof(arr.map!(n => n).each!((ref n) => n++)))); // The default predicate consumes the range auto m = arr.map!(n => n); (&m).each(); assert(m.empty); // Indexes are also available for in-place mutations arr[] = 0; arr.each!"a=i"(); assert(arr == [0, 1, 2, 3, 4]); // opApply iterators work as well static class S { int x; int opApply(scope int delegate(ref int _x) dg) { return dg(x); } } auto s = new S; s.each!"a++"; assert(s.x == 1);
- template
filter
(alias predicate) if (is(typeof(unaryFun!predicate))) - auto
filter
(Range)(Range rs) if (isInputRange!(Unqual!Range));Implements the higher order filter function. The predicate is passed to std.functional.unaryFun, and can either accept a string, or any callable that can be executed via pred(element).Parameters:predicate Function to apply to each element of range Range range Input range of elements Returns:filter
!(predicate)(range) returns a new range containing only elements x in range for which predicate(x) returnstrue
.See Also:Examples:import std.algorithm.comparison : equal; import std.math : approxEqual; import std.range; int[] arr = [ 1, 2, 3, 4, 5 ]; // Sum all elements auto small = filter!(a => a < 3)(arr); assert(equal(small, [ 1, 2 ])); // Sum again, but with Uniform Function Call Syntax (UFCS) auto sum = arr.filter!(a => a < 3); assert(equal(sum, [ 1, 2 ])); // In combination with chain() to span multiple ranges int[] a = [ 3, -2, 400 ]; int[] b = [ 100, -101, 102 ]; auto r = chain(a, b).filter!(a => a > 0); assert(equal(r, [ 3, 400, 100, 102 ])); // Mixing convertible types is fair game, too double[] c = [ 2.5, 3.0 ]; auto r1 = chain(c, a, b).filter!(a => cast(int) a != a); assert(approxEqual(r1, [ 2.5 ]));
- template
filterBidirectional
(alias pred) - auto
filterBidirectional
(Range)(Range r) if (isBidirectionalRange!(Unqual!Range));Similar to filter, except it defines a bidirectional range. There is a speed disadvantage - the constructor spends time finding the last element in the range that satisfies the filtering condition (in addition to finding the first one). The advantage is that the filtered range can be spanned from both directions. Also, std.range.retro can be applied against the filtered range. The predicate is passed to std.functional.unaryFun, and can either accept a string, or any callable that can be executed via pred(element).Parameters:pred Function to apply to each element of range Range r Bidirectional range of elements Returns:a new range containing only the elements in r for which pred returnstrue
.Examples:import std.algorithm.comparison : equal; import std.range; int[] arr = [ 1, 2, 3, 4, 5 ]; auto small = filterBidirectional!("a < 3")(arr); static assert(isBidirectionalRange!(typeof(small))); assert(small.back == 2); assert(equal(small, [ 1, 2 ])); assert(equal(retro(small), [ 2, 1 ])); // In combination with chain() to span multiple ranges int[] a = [ 3, -2, 400 ]; int[] b = [ 100, -101, 102 ]; auto r = filterBidirectional!("a > 0")(chain(a, b)); assert(r.back == 102);
- Group!(pred, Range)
group
(alias pred = "a == b", Range)(Ranger
);
structGroup
(alias pred, R) if (isInputRange!R); - Groups consecutively equivalent elements into a single tuple of the element and the number of its repetitions.Similarly to uniq,
group
produces a range that iterates over unique consecutive elements of the given range. Each element of this range is a tuple of the element and the number of times it is repeated in the original range. Equivalence of elements is assessed by using the predicate pred, which defaults to "a == b". The predicate is passed to std.functional.binaryFun, and can either accept a string, or any callable that can be executed via pred(element, element).Parameters:pred Binary predicate for determining equivalence of two elements. Range r
The input range to iterate over. Returns:A range of elements of type Tuple!(ElementType!R, uint), representing each consecutively unique element and its respective number of occurrences in that run. This will be an input range if R is an input range, and a forward range in all other cases.Examples:import std.algorithm.comparison : equal; import std.typecons : tuple, Tuple; int[] arr = [ 1, 2, 2, 2, 2, 3, 4, 4, 4, 5 ]; assert(equal(group(arr), [ tuple(1, 1u), tuple(2, 4u), tuple(3, 1u), tuple(4, 3u), tuple(5, 1u) ][]));
- auto
chunkBy
(alias pred, Range)(Ranger
)
if (isInputRange!Range); - Chunks an input range into subranges of equivalent adjacent elements.Equivalence is defined by the predicate pred, which can be either binary, which is passed to std.functional.binaryFun, or unary, which is passed to std.functional.unaryFun. In the binary form, two range elements a and b are considered equivalent if pred(a,b) is
true
. In unary form, two elements are considered equivalent if pred(a) == pred(b) istrue
. This predicate must be an equivalence relation, that is, it must be reflexive (pred(x,x) is alwaystrue
), symmetric (pred(x,y) == pred(y,x)), and transitive (pred(x,y) && pred(y,z) implies pred(x,z)). If this is not the case, the range returned bychunkBy
may assert at runtime or behave erratically.Parameters:pred Predicate for determining equivalence. Range r
The range to be chunked. Returns:With a binary predicate, a range of ranges is returned in which all elements in a given subrange are equivalent under the given predicate. With a unary predicate, a range of tuples is returned, with the tuple consisting of the result of the unary predicate for each subrange, and the subrange itself.Notes: Equivalent elements separated by an intervening non-equivalent element will appear in separate subranges; this function only considers adjacent equivalence. Elements in the subranges will always appear in the same order they appear in the original range.
See Also:group, which collapses adjacent equivalent elements into a single element.Examples:Showing usage with binary predicate:import std.algorithm.comparison : equal; // Grouping by particular attribute of each element: auto data = [ [1, 1], [1, 2], [2, 2], [2, 3] ]; auto r1 = data.chunkBy!((a,b) => a[0] == b[0]); assert(r1.equal!equal([ [[1, 1], [1, 2]], [[2, 2], [2, 3]] ])); auto r2 = data.chunkBy!((a,b) => a[1] == b[1]); assert(r2.equal!equal([ [[1, 1]], [[1, 2], [2, 2]], [[2, 3]] ]));
Examples:Showing usage with unary predicate:import std.algorithm.comparison : equal; import std.typecons : tuple; import std.range.primitives; // Grouping by particular attribute of each element: auto range = [ [1, 1], [1, 1], [1, 2], [2, 2], [2, 3], [2, 3], [3, 3] ]; auto byX = chunkBy!(a => a[0])(range); auto expected1 = [ tuple(1, [[1, 1], [1, 1], [1, 2]]), tuple(2, [[2, 2], [2, 3], [2, 3]]), tuple(3, [[3, 3]]) ]; foreach (e; byX) { assert(!expected1.empty); assert(e[0] == expected1.front[0]); assert(e[1].equal(expected1.front[1])); expected1.popFront(); } auto byY = chunkBy!(a => a[1])(range); auto expected2 = [ tuple(1, [[1, 1], [1, 1]]), tuple(2, [[1, 2], [2, 2]]), tuple(3, [[2, 3], [2, 3], [3, 3]]) ]; foreach (e; byY) { assert(!expected2.empty); assert(e[0] == expected2.front[0]); assert(e[1].equal(expected2.front[1])); expected2.popFront(); }
- auto
joiner
(RoR, Separator)(RoRr
, Separatorsep
)
if (isInputRange!RoR && isInputRange!(ElementType!RoR) && isForwardRange!Separator && is(ElementType!Separator : ElementType!(ElementType!RoR)));
autojoiner
(RoR)(RoRr
)
if (isInputRange!RoR && isInputRange!(ElementType!RoR)); - Lazily joins a range of ranges with a separator. The separator itself is a range. If a separator is not provided, then the ranges are joined directly without anything in between them (often called flatten in other languages).Parameters:
RoR r
An input range of input ranges to be joined. Separator sep
A forward range of element(s) to serve as separators in the joined range. Returns:A range of elements in the joined range. This will be a forward range if both outer and inner ranges of RoR are forward ranges; otherwise it will be only an input range.See Also:std.range.chain, which chains a sequence of ranges with compatible elements into a single range.Examples:import std.algorithm.comparison : equal; import std.conv : text; assert(["abc", "def"].joiner.equal("abcdef")); assert(["Mary", "has", "a", "little", "lamb"] .joiner("...") .equal("Mary...has...a...little...lamb")); assert(["", "abc"].joiner("xyz").equal("xyzabc")); assert([""].joiner("xyz").equal("")); assert(["", ""].joiner("xyz").equal("xyz"));
- template
reduce
(fun...) if (fun.length >= 1) - 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 versionreduce
!(fun)(range) works similarly, but it uses the first element of the range as the seed (the range must be non-empty).Returns:the accumulated resultSee Also:Fold (higher-order function) fold is functionally equivalent toreduce
">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 toreduce
!((a, b) => a + b) that offers pairwise summing of floating point numbers.Examples:Many aggregate range operations turn out to be solved withreduce
quickly and easily. The example below illustratesreduce
's remarkable power and flexibility.import std.algorithm.comparison : max, min; import std.math : approxEqual; import std.range; int[] arr = [ 1, 2, 3, 4, 5 ]; // Sum all elements auto sum = reduce!((a,b) => a + b)(0, arr); assert(sum == 15); // Sum again, using a string predicate with "a" and "b" sum = reduce!"a + b"(0, arr); assert(sum == 15); // Compute the maximum of all elements auto largest = reduce!(max)(arr); assert(largest == 5); // Max again, but with Uniform Function Call Syntax (UFCS) largest = arr.reduce!(max); assert(largest == 5); // Compute the number of odd elements auto odds = reduce!((a,b) => a + (b & 1))(0, arr); assert(odds == 3); // Compute the sum of squares auto ssquares = reduce!((a,b) => a + b * b)(0, arr); assert(ssquares == 55); // Chain multiple ranges into seed int[] a = [ 3, 4 ]; int[] b = [ 100 ]; auto r = reduce!("a + b")(chain(a, b)); assert(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(approxEqual(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(approxEqual(r2, 112.5));
Examples: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 whyreduce
accepts multiple functions. If two or more functions are passed,reduce
returns a std.typecons.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 : approxEqual, 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(approxEqual(r[0], 2)); // minimum assert(approxEqual(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(approxEqual(r[0], 35)); // sum assert(approxEqual(r[1], 233)); // sum of squares // Compute average and standard deviation from the above auto avg = r[0] / a.length; auto stdev = sqrt(r[1] / a.length - avg * avg);
- auto
reduce
(R)(Rr
)
if (isIterable!R); - No-seed version. The first element of
r
is used as the seed's value.For each function f in fun, the corresponding seed type S is Unqual!(typeof(f(e, e))), where e is an element ofr
: ElementType!R for ranges, and ForeachType!R otherwise. Once S has been determined, then S s = e; and s = f(s, e); must both be legal. Ifr
is empty, an Exception is thrown.Parameters:R r
an iterable value as defined by isIterable Returns:the final result of the accumulator applied to the iterable - auto
reduce
(S, R)(Sseed
, Rr
)
if (isIterable!R); - Seed version. The
seed
should be a single value if fun is a single function. If fun is multiple functions, thenseed
should be a std.typecons.Tuple, with one field per function in f.For convenience, if theseed
is const, or has qualified fields, thenreduce
will operate on an unqualified copy. If this happens then the returned type will not perfectly match S. Use fold instead ofreduce
to use theseed
version in a UFCS chain.Parameters:S seed
the initial value of the accumulator R r
an iterable value as defined by isIterable Returns:the final result of the accumulator applied to the iterable
- template
fold
(fun...) if (fun.length >= 1) - Implements the homonym function (also known as accumulate, compress, inject, or foldl) present in various programming languages of functional flavor. The call
fold
!(fun)(range, seed) 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 versionfold
!(fun)(range) works similarly, but it uses the first element of the range as the seed (the range must be non-empty).Returns:the accumulated resultSee Also:Fold (higher-order function) sum is similar tofold
!((a, b) => a + b) that offers precise summing of floating point numbers. This is functionally equivalent to reduce with the argument order reversed, and without the need to use tuple for multiple seeds.Examples:immutable arr = [1, 2, 3, 4, 5]; // Sum all elements assert(arr.fold!((a, b) => a + b) == 15); // Sum all elements with explicit seed assert(arr.fold!((a, b) => a + b)(6) == 21); import std.algorithm.comparison : min, max; import std.typecons : tuple; // Compute minimum and maximum at the same time assert(arr.fold!(min, max) == tuple(1, 5)); // Compute minimum and maximum at the same time with seeds assert(arr.fold!(min, max)(0, 7) == tuple(0, 7)); // Can be used in a UFCS chain assert(arr.map!(a => a + 1).fold!((a, b) => a + b) == 20);
- template
cumulativeFold
(fun...) if (fun.length >= 1) - Similar to fold, but returns a range containing the successive reduced values. The call
cumulativeFold
!(fun)(range, seed) first assigns seed to an internal variable result, also called the accumulator. The returned range contains the values result = fun(result, x) lazily evaluated for each element x in range. Finally, the last element has the same value as fold!(fun)(seed, range). The one-argument versioncumulativeFold
!(fun)(range) works similarly, but it returns the first element unchanged and uses it as seed for the next elements. This function is also known as partial_sum, accumulate, scan, Cumulative Sum.Returns:The function returns a range containing the consecutive reduced values. If there is more than one fun, the element type will be std.typecons.Tuple containing one element for each fun.See Also:Examples:import std.algorithm.comparison : max, min; import std.array : array; import std.math : approxEqual; import std.range : chain; int[] arr = [1, 2, 3, 4, 5]; // Partial sum of all elements auto sum = cumulativeFold!((a, b) => a + b)(arr, 0); assert(sum.array == [1, 3, 6, 10, 15]); // Partial sum again, using a string predicate with "a" and "b" auto sum2 = cumulativeFold!"a + b"(arr, 0); assert(sum2.array == [1, 3, 6, 10, 15]); // Compute the partial maximum of all elements auto largest = cumulativeFold!max(arr); assert(largest.array == [1, 2, 3, 4, 5]); // Partial max again, but with Uniform Function Call Syntax (UFCS) largest = arr.cumulativeFold!max; assert(largest.array == [1, 2, 3, 4, 5]); // Partial count of odd elements auto odds = arr.cumulativeFold!((a, b) => a + (b & 1))(0); assert(odds.array == [1, 1, 2, 2, 3]); // Compute the partial sum of squares auto ssquares = arr.cumulativeFold!((a, b) => a + b * b)(0); assert(ssquares.array == [1, 5, 14, 30, 55]); // Chain multiple ranges into seed int[] a = [3, 4]; int[] b = [100]; auto r = cumulativeFold!"a + b"(chain(a, b)); assert(r.array == [3, 7, 107]); // Mixing convertible types is fair game, too double[] c = [2.5, 3.0]; auto r1 = cumulativeFold!"a + b"(chain(a, b, c)); assert(approxEqual(r1, [3, 7, 107, 109.5, 112.5])); // To minimize nesting of parentheses, Uniform Function Call Syntax can be used auto r2 = chain(a, b, c).cumulativeFold!"a + b"; assert(approxEqual(r2, [3, 7, 107, 109.5, 112.5]));
Examples: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 whycumulativeFold
accepts multiple functions. If two or more functions are passed,cumulativeFold
returns a std.typecons.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.algorithm.iteration : map; import std.math : approxEqual; import std.typecons : tuple; double[] a = [3.0, 4, 7, 11, 3, 2, 5]; // Compute minimum and maximum in one pass auto r = a.cumulativeFold!(min, max); // The type of r is Tuple!(int, int) assert(approxEqual(r.map!"a[0]", [3, 3, 3, 3, 3, 2, 2])); // minimum assert(approxEqual(r.map!"a[1]", [3, 4, 7, 11, 11, 11, 11])); // maximum // Compute sum and sum of squares in one pass auto r2 = a.cumulativeFold!("a + b", "a + b * b")(tuple(0.0, 0.0)); assert(approxEqual(r2.map!"a[0]", [3, 7, 14, 25, 28, 30, 35])); // sum assert(approxEqual(r2.map!"a[1]", [9, 25, 74, 195, 204, 208, 233])); // sum of squares
- auto
cumulativeFold
(R)(Rrange
)
if (isInputRange!(Unqual!R)); - No-seed version. The first element of r is used as the seed's value. For each function f in fun, the corresponding seed type S is Unqual!(typeof(f(e, e))), where e is an element of r: ElementType!R. Once S has been determined, then S s = e; and s = f(s, e); must both be legal.Parameters:
R range
an input range
as defined by isInputRangeReturns:arange
containing the consecutive reduced values. - auto
cumulativeFold
(R, S)(Rrange
, Sseed
)
if (isInputRange!(Unqual!R)); - Seed version. The
seed
should be a single value if fun is a single function. If fun is multiple functions, thenseed
should be a std.typecons.Tuple, with one field per function in f. For convenience, if theseed
is const, or has qualified fields, thencumulativeFold
will operate on an unqualified copy. If this happens then the returned type will not perfectly match S.Parameters:R range
an input range
as defined by isInputRangeS seed
the initial value of the accumulator Returns:arange
containing the consecutive reduced values.
- auto
splitter
(alias pred = "a == b", Range, Separator)(Ranger
, Separators
)
if (is(typeof(binaryFun!pred(r
.front,s
)) : bool) && (hasSlicing!Range && hasLength!Range || isNarrowString!Range)); - Lazily splits a range using an element as a separator. This can be used with any narrow string type or sliceable range type, but is most popular with string types.Two adjacent separators are considered to surround an empty element in the split range. Use filter!(a => !a.empty) on the result to compress empty elements. The predicate is passed to std.functional.binaryFun, and can either accept a string, or any callable that can be executed via pred(element,
s
). If the empty range is given, the result is a range with one empty element. If a range with one separator is given, the result is a range with two empty elements. If splitting a string on whitespace and token compression is desired, consider usingsplitter
without specifying a separator (see fourth overload below).Parameters:pred The predicate for comparing each element with the separator, defaulting to "a == b". Range r
The input range to be split. Must support slicing and .length. Separator s
The element to be treated as the separator between range segments to be split. Constraints: The predicate pred needs to accept an element of
r
and the separators
.Returns:An input range of the subranges of elements between separators. Ifr
is a forward range or bidirectional range, the returned range will be likewise.See Also:std.regex.splitter for a version that splits using a regular expression defined separator.Examples:import std.algorithm.comparison : equal; assert(equal(splitter("hello world", ' '), [ "hello", "", "world" ])); int[] a = [ 1, 2, 0, 0, 3, 0, 4, 5, 0 ]; int[][] w = [ [1, 2], [], [3], [4, 5], [] ]; assert(equal(splitter(a, 0), w)); a = [ 0 ]; assert(equal(splitter(a, 0), [ (int[]).init, (int[]).init ])); a = [ 0, 1 ]; assert(equal(splitter(a, 0), [ [], [1] ])); w = [ [0], [1], [2] ]; assert(equal(splitter!"a.front == b"(w, 1), [ [[0]], [[2]] ]));
- auto
splitter
(alias pred = "a == b", Range, Separator)(Ranger
, Separators
)
if (is(typeof(binaryFun!pred(r
.front,s
.front)) : bool) && (hasSlicing!Range || isNarrowString!Range) && isForwardRange!Separator && (hasLength!Separator || isNarrowString!Separator)); - Similar to the previous overload of
splitter
, except this one uses another range as a separator. This can be used with any narrow string type or sliceable range type, but is most popular with string types. The predicate is passed to std.functional.binaryFun, and can either accept a string, or any callable that can be executed via pred(r
.front,s
.front).Two adjacent separators are considered to surround an empty element in the split range. Use filter!(a => !a.empty) on the result to compress empty elements.Parameters:pred The predicate for comparing each element with the separator, defaulting to "a == b". Range r
The input range to be split. Separator s
The forward range to be treated as the separator between segments of r
to be split.Constraints: The predicate pred needs to accept an element of
r
and an element ofs
.Returns:An input range of the subranges of elements between separators. Ifr
is a forward range or bidirectional range, the returned range will be likewise.See Also:std.regex.splitter for a version that splits using a regular expression defined separator.Examples:import std.algorithm.comparison : equal; assert(equal(splitter("hello world", " "), [ "hello", "world" ])); int[] a = [ 1, 2, 0, 0, 3, 0, 4, 5, 0 ]; int[][] w = [ [1, 2], [3, 0, 4, 5, 0] ]; assert(equal(splitter(a, [0, 0]), w)); a = [ 0, 0 ]; assert(equal(splitter(a, [0, 0]), [ (int[]).init, (int[]).init ])); a = [ 0, 0, 1 ]; assert(equal(splitter(a, [0, 0]), [ [], [1] ]));
- auto
splitter
(alias isTerminator, Range)(Rangeinput
)
if (isForwardRange!Range && is(typeof(unaryFun!isTerminator(input
.front)))); - Similar to the previous overload of
splitter
, except this one does not use a separator. Instead, the predicate is an unary function on theinput
range's element type. The isTerminator predicate is passed to std.functional.unaryFun and can either accept a string, or any callable that can be executed via pred(element, s).Two adjacent separators are considered to surround an empty element in the split range. Use filter!(a => !a.empty) on the result to compress empty elements.Parameters:isTerminator The predicate for deciding where to split the range. Range input
The input
range to be split.Constraints: The predicate isTerminator needs to accept an element of
input
.Returns:Aninput
range of the subranges of elements between separators. Ifinput
is a forward range or bidirectional range, the returned range will be likewise.See Also:std.regex.splitter for a version that splits using a regular expression defined separator.Examples:import std.algorithm.comparison : equal; import std.range.primitives : front; assert(equal(splitter!(a => a == ' ')("hello world"), [ "hello", "", "world" ])); int[] a = [ 1, 2, 0, 0, 3, 0, 4, 5, 0 ]; int[][] w = [ [1, 2], [], [3], [4, 5], [] ]; assert(equal(splitter!(a => a == 0)(a), w)); a = [ 0 ]; assert(equal(splitter!(a => a == 0)(a), [ (int[]).init, (int[]).init ])); a = [ 0, 1 ]; assert(equal(splitter!(a => a == 0)(a), [ [], [1] ])); w = [ [0], [1], [2] ]; assert(equal(splitter!(a => a.front == 1)(w), [ [[0]], [[2]] ]));
- auto
splitter
(C)(C[]s
)
if (isSomeChar!C); - Lazily splits the string
s
into words, using whitespace as the delimiter.This function is string specific and, contrary tosplitter
!(std.uni.isWhite), runs of whitespace will be merged together (no empty tokens will be produced).Parameters:C[] s
The string to be split. Returns:An input range of slices of the original string split by whitespace.Examples:import std.algorithm.comparison : equal; auto a = " a bcd ef gh "; assert(equal(splitter(a), ["a", "bcd", "ef", "gh"][]));
- auto
sum
(R)(Rr
)
if (isInputRange!R && !isInfinite!R && is(typeof(r
.front +r
.front)));
autosum
(R, E)(Rr
, Eseed
)
if (isInputRange!R && !isInfinite!R && is(typeof(seed
=seed
+r
.front))); - Sums elements of
r
, which must be a finite input range. Although conceptuallysum
(r
) is equivalent to fold!((a, b) => a + b)(r
, 0),sum
uses specialized algorithms to maximize accuracy, as follows.- If std.range.primitives.ElementType!R is a floating-point
type and R is a
random-access range with
length and slicing, then
sum
uses the pairwise summation algorithm. - If ElementType!R is a floating-point type and R is a
finite input range (but not a random-access range with slicing), then
sum
uses the Kahan summation algorithm. - In all other cases, a simple element by element addition is done.
seed
may be passed tosum
. Not only will thisseed
be used as an initial value, but its type will override all the above, and determine the algorithm and precision used for summation. Note that these specialized summing algorithms execute more primitive operations than vanilla summation. Therefore, if in certain cases maximum speed is required at expense of precision, one can use fold!((a, b) => a + b)(r
, 0), which is not specialized for summation.Parameters:E seed
the initial value of the summation R r
a finite input range Returns:Thesum
of all the elements in the ranger
. - If std.range.primitives.ElementType!R is a floating-point
type and R is a
random-access range with
length and slicing, then
- auto
uniq
(alias pred = "a == b", Range)(Ranger
)
if (isInputRange!Range && is(typeof(binaryFun!pred(r
.front,r
.front)) == bool)); - Lazily iterates unique consecutive elements of the given range (functionality akin to the uniq system utility). Equivalence of elements is assessed by using the predicate pred, by default "a == b". The predicate is passed to std.functional.binaryFun, and can either accept a string, or any callable that can be executed via pred(element, element). If the given range is bidirectional,
uniq
also yields a bidirectional range.Parameters:pred Predicate for determining equivalence between range elements. Range r
An input range of elements to filter. Returns:An input range of consecutively unique elements in the original range. Ifr
is also a forward range or bidirectional range, the returned range will be likewise.Examples:import std.algorithm.mutation : copy; import std.algorithm.comparison : equal; int[] arr = [ 1, 2, 2, 2, 2, 3, 4, 4, 4, 5 ]; assert(equal(uniq(arr), [ 1, 2, 3, 4, 5 ][])); // Filter duplicates in-place using copy arr.length -= arr.uniq().copy(arr).length; assert(arr == [ 1, 2, 3, 4, 5 ]); // Note that uniqueness is only determined consecutively; duplicated // elements separated by an intervening different element will not be // eliminated: assert(equal(uniq([ 1, 1, 2, 1, 1, 3, 1]), [1, 2, 1, 3, 1]));
Examples:import std.algorithm.comparison : equal; struct S { int i; string s; } auto arr = [ S(1, "a"), S(1, "b"), S(2, "c"), S(2, "d") ]; // Let's consider just the 'i' member for equality auto r = arr.uniq!((a, b) => a.i == b.i); assert(r.equal([S(1, "a"), S(2, "c")])); assert(r.front == S(1, "a")); assert(r.back == S(2, "c")); r.popBack; assert(r.back == S(1, "a")); assert(r.front == r.back); r.popBack; assert(r.empty); import std.exception : assertThrown; assertThrown!Error(r.front); assertThrown!Error(r.back); assertThrown!Error(r.popFront); assertThrown!Error(r.popBack);
- Permutations!Range
permutations
(Range)(Ranger
)
if (isRandomAccessRange!Range && hasLength!Range);
structPermutations
(Range) if (isRandomAccessRange!Range && hasLength!Range); - Lazily computes all permutations of
r
using Heap's algorithm.Returns:A forward range the elements of which are an std.range.indexed view intor
.See Also:Examples:import std.algorithm.comparison : equal; import std.range : iota; assert(equal!equal(iota(3).permutations, [[0, 1, 2], [1, 0, 2], [2, 0, 1], [0, 2, 1], [1, 2, 0], [2, 1, 0]]));
Andrei Alexandrescu 2008-.
| Page generated by
Ddoc on (no date time)