|  | @safe unittest | 
|  | { | 
|  | import std.algorithm.iteration; | 
|  |  | 
|  | import std.algorithm.comparison : equal; | 
|  | import std.range, std.stdio; | 
|  | 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); | 
|  | } | 
|  |  | 
|  | @safe unittest | 
|  | { | 
|  | import std.algorithm.iteration; | 
|  |  | 
|  | 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. | 
|  | } | 
|  |  | 
|  | @safe @nogc unittest | 
|  | { | 
|  | import std.algorithm.iteration; | 
|  |  | 
|  | import std.algorithm.comparison : equal; | 
|  | import std.range : chain, only; | 
|  | auto squares = | 
|  | chain(only(1, 2, 3, 4), only(5, 6)).map!(a => a * a); | 
|  | assert(equal(squares, only(1, 4, 9, 16, 25, 36))); | 
|  | } | 
|  |  | 
|  | @safe unittest | 
|  | { | 
|  | import std.algorithm.iteration; | 
|  |  | 
|  | 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; | 
|  | } | 
|  | } | 
|  |  | 
|  | @safe unittest | 
|  | { | 
|  | import std.algorithm.iteration; | 
|  |  | 
|  | 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" ])); | 
|  | } | 
|  |  | 
|  | @safe unittest | 
|  | { | 
|  | import std.algorithm.iteration; | 
|  |  | 
|  | import std.range : iota; | 
|  | import std.typecons : No; | 
|  |  | 
|  | int[] arr; | 
|  | iota(5).each!(n => arr ~= n); | 
|  | assert(arr == [0, 1, 2, 3, 4]); | 
|  |  | 
|  | // stop iterating early | 
|  | iota(5).each!((n) { arr ~= n; return No.each; }); | 
|  | assert(arr == [0, 1, 2, 3, 4, 0]); | 
|  |  | 
|  | // If the range supports it, the value can be mutated in place | 
|  | arr.each!((ref n) => n++); | 
|  | assert(arr == [1, 2, 3, 4, 5, 1]); | 
|  |  | 
|  | arr.each!"a++"; | 
|  | assert(arr == [2, 3, 4, 5, 6, 2]); | 
|  |  | 
|  | auto m = arr.map!(n => n); | 
|  | // by-ref lambdas are not allowed for non-ref ranges | 
|  | static assert(!__traits(compiles, m.each!((ref n) => n++))); | 
|  |  | 
|  | // The default predicate consumes the range | 
|  | (&m).each(); | 
|  | assert(m.empty); | 
|  | } | 
|  |  | 
|  | @safe unittest | 
|  | { | 
|  | import std.algorithm.iteration; | 
|  |  | 
|  | auto arr = new size_t[4]; | 
|  |  | 
|  | arr.each!"a=i"(); | 
|  | assert(arr == [0, 1, 2, 3]); | 
|  |  | 
|  | arr.each!((i, ref e) => e = i * 2); | 
|  | assert(arr == [0, 2, 4, 6]); | 
|  | } | 
|  |  | 
|  | @system unittest | 
|  | { | 
|  | import std.algorithm.iteration; | 
|  |  | 
|  | 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); | 
|  | } | 
|  |  | 
|  | @safe unittest | 
|  | { | 
|  | import std.algorithm.iteration; | 
|  |  | 
|  | import std.algorithm.comparison : equal; | 
|  | import std.math.operations : isClose; | 
|  | import std.range; | 
|  |  | 
|  | int[] arr = [ 1, 2, 3, 4, 5 ]; | 
|  |  | 
|  | // Filter below 3 | 
|  | auto small = filter!(a => a < 3)(arr); | 
|  | assert(equal(small, [ 1, 2 ])); | 
|  |  | 
|  | // Filter 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(isClose(r1, [ 2.5 ])); | 
|  | } | 
|  |  | 
|  | @safe unittest | 
|  | { | 
|  | import std.algorithm.iteration; | 
|  |  | 
|  | 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); | 
|  | } | 
|  |  | 
|  | @safe unittest | 
|  | { | 
|  | import std.algorithm.iteration; | 
|  |  | 
|  | 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) ][])); | 
|  | } | 
|  |  | 
|  | @safe unittest | 
|  | { | 
|  | import std.algorithm.iteration; | 
|  |  | 
|  | import std.algorithm.sorting : sort; | 
|  | import std.array : assocArray; | 
|  |  | 
|  | uint[string] result; | 
|  | auto range = ["a", "b", "a", "c", "b", "c", "c", "d", "e"]; | 
|  | result = range.sort!((a, b) => a < b) | 
|  | .group | 
|  | .assocArray; | 
|  |  | 
|  | assert(result == ["a": 2U, "b": 2U, "c": 3U, "d": 1U, "e": 1U]); | 
|  | } | 
|  |  | 
|  | @safe unittest | 
|  | { | 
|  | import std.algorithm.iteration; | 
|  |  | 
|  | 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]] | 
|  | ])); | 
|  | } | 
|  |  | 
|  | @safe unittest | 
|  | { | 
|  | import std.algorithm.iteration; | 
|  |  | 
|  | import std.algorithm.comparison : equal; | 
|  | import std.range.primitives; | 
|  | import std.typecons : tuple; | 
|  |  | 
|  | // 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(); | 
|  | } | 
|  | } | 
|  |  | 
|  | nothrow pure @safe unittest | 
|  | { | 
|  | import std.algorithm.iteration; | 
|  |  | 
|  | import std.algorithm.comparison : equal; | 
|  | import std.range : dropExactly; | 
|  | auto source = [4, 3, 2, 11, 0, -3, -3, 5, 3, 0]; | 
|  |  | 
|  | auto result1 = source.splitWhen!((a,b) => a <= b); | 
|  | assert(result1.save.equal!equal([ | 
|  | [4, 3, 2], | 
|  | [11, 0, -3], | 
|  | [-3], | 
|  | [5, 3, 0] | 
|  | ])); | 
|  |  | 
|  | //splitWhen, like chunkBy, is currently a reference range (this may change | 
|  | //in future). Remember to call `save` when appropriate. | 
|  | auto result2 = result1.dropExactly(2); | 
|  | assert(result1.save.equal!equal([ | 
|  | [-3], | 
|  | [5, 3, 0] | 
|  | ])); | 
|  | } | 
|  |  | 
|  | @safe unittest | 
|  | { | 
|  | import std.algorithm.iteration; | 
|  |  | 
|  | 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")); | 
|  | } | 
|  |  | 
|  | @safe unittest | 
|  | { | 
|  | import std.algorithm.iteration; | 
|  |  | 
|  | import std.algorithm.comparison : equal; | 
|  | import std.range : repeat; | 
|  |  | 
|  | assert([""].joiner.equal("")); | 
|  | assert(["", ""].joiner.equal("")); | 
|  | assert(["", "abc"].joiner.equal("abc")); | 
|  | assert(["abc", ""].joiner.equal("abc")); | 
|  | assert(["abc", "def"].joiner.equal("abcdef")); | 
|  | assert(["Mary", "has", "a", "little", "lamb"].joiner.equal("Maryhasalittlelamb")); | 
|  | assert("abc".repeat(3).joiner.equal("abcabcabc")); | 
|  | } | 
|  |  | 
|  | @safe unittest | 
|  | { | 
|  | import std.algorithm.iteration; | 
|  |  | 
|  | import std.algorithm.comparison : equal; | 
|  | auto a = [ [1, 2, 3], [42, 43] ]; | 
|  | auto j = joiner(a); | 
|  | j.front = 44; | 
|  | assert(a == [ [44, 2, 3], [42, 43] ]); | 
|  | assert(equal(j, [44, 2, 3, 42, 43])); | 
|  | } | 
|  |  | 
|  | @safe pure unittest | 
|  | { | 
|  | import std.algorithm.iteration; | 
|  |  | 
|  | import std.algorithm.comparison : equal; | 
|  | import std.range : chain, cycle, iota, only, retro, take, zip; | 
|  | import std.format : format; | 
|  |  | 
|  | static immutable number = "12345678"; | 
|  | static immutable delimiter = ","; | 
|  | auto formatted = number.retro | 
|  | .zip(3.iota.cycle.take(number.length)) | 
|  | .map!(z => chain(z[0].only, z[1] == 2 ? delimiter : null)) | 
|  | .joiner | 
|  | .retro; | 
|  | static immutable expected = "12,345,678"; | 
|  | assert(formatted.equal(expected)); | 
|  | } | 
|  |  | 
|  | @safe unittest | 
|  | { | 
|  | import std.algorithm.iteration; | 
|  |  | 
|  | import std.algorithm.comparison : equal; | 
|  | import std.range : retro; | 
|  |  | 
|  | auto a = [[1, 2, 3], [4, 5]]; | 
|  | auto j = a.joiner; | 
|  | j.back = 44; | 
|  | assert(a == [[1, 2, 3], [4, 44]]); | 
|  | assert(equal(j.retro, [44, 4, 3, 2, 1])); | 
|  | } | 
|  |  | 
|  | @safe unittest | 
|  | { | 
|  | import std.algorithm.iteration; | 
|  |  | 
|  | 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); | 
|  | 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(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)); | 
|  | } | 
|  |  | 
|  | @safe unittest | 
|  | { | 
|  | import std.algorithm.iteration; | 
|  |  | 
|  | 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; | 
|  | assert(avg == 5); | 
|  | auto stdev = sqrt(r[1] / a.length - avg * avg); | 
|  | assert(cast(int) stdev == 2); | 
|  | } | 
|  |  | 
|  | @safe pure unittest | 
|  | { | 
|  | import std.algorithm.iteration; | 
|  |  | 
|  | immutable arr = [1, 2, 3, 4, 5]; | 
|  |  | 
|  | // Sum all elements | 
|  | assert(arr.fold!((a, e) => a + e) == 15); | 
|  |  | 
|  | // Sum all elements with explicit seed | 
|  | assert(arr.fold!((a, e) => a + e)(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, e) => a + e) == 20); | 
|  |  | 
|  | // Return the last element of any range | 
|  | assert(arr.fold!((a, e) => e) == 5); | 
|  | } | 
|  |  | 
|  | @safe unittest | 
|  | { | 
|  | import std.algorithm.iteration; | 
|  |  | 
|  | import std.algorithm.comparison : max, min; | 
|  | import std.array : array; | 
|  | import std.math.operations : isClose; | 
|  | 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(isClose(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(isClose(r2, [3, 7, 107, 109.5, 112.5])); | 
|  | } | 
|  |  | 
|  | @safe unittest | 
|  | { | 
|  | import std.algorithm.iteration; | 
|  |  | 
|  | import std.algorithm.comparison : max, min; | 
|  | import std.algorithm.iteration : map; | 
|  | import std.math.operations : isClose; | 
|  | 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(isClose(r.map!"a[0]", [3, 3, 3, 3, 3, 2, 2]));     // minimum | 
|  | assert(isClose(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(isClose(r2.map!"a[0]", [3, 7, 14, 25, 28, 30, 35]));      // sum | 
|  | assert(isClose(r2.map!"a[1]", [9, 25, 74, 195, 204, 208, 233])); // sum of squares | 
|  | } | 
|  |  | 
|  | @safe unittest | 
|  | { | 
|  | import std.algorithm.iteration; | 
|  |  | 
|  | import std.algorithm.comparison : equal; | 
|  |  | 
|  | assert("a|bc|def".splitter('|').equal([ "a", "bc", "def" ])); | 
|  |  | 
|  | int[] a = [1, 0, 2, 3, 0, 4, 5, 6]; | 
|  | int[][] w = [ [1], [2, 3], [4, 5, 6] ]; | 
|  | assert(a.splitter(0).equal(w)); | 
|  | } | 
|  |  | 
|  | @safe unittest | 
|  | { | 
|  | import std.algorithm.iteration; | 
|  |  | 
|  | import std.algorithm.comparison : equal; | 
|  | import std.typecons : Yes; | 
|  |  | 
|  | assert("a|bc|def".splitter!("a == b", Yes.keepSeparators)('|') | 
|  | .equal([ "a", "|", "bc", "|", "def" ])); | 
|  |  | 
|  | int[] a = [1, 0, 2, 3, 0, 4, 5, 6]; | 
|  | int[][] w = [ [1], [0], [2, 3], [0], [4, 5, 6] ]; | 
|  | assert(a.splitter!("a == b", Yes.keepSeparators)(0).equal(w)); | 
|  | } | 
|  |  | 
|  | @safe unittest | 
|  | { | 
|  | import std.algorithm.iteration; | 
|  |  | 
|  | import std.algorithm.comparison : equal; | 
|  |  | 
|  | assert("|ab|".splitter('|').equal([ "", "ab", "" ])); | 
|  | assert("ab".splitter('|').equal([ "ab" ])); | 
|  |  | 
|  | assert("a|b||c".splitter('|').equal([ "a", "b", "", "c" ])); | 
|  | assert("hello  world".splitter(' ').equal([ "hello", "", "world" ])); | 
|  |  | 
|  | auto a = [ 1, 2, 0, 0, 3, 0, 4, 5, 0 ]; | 
|  | auto w = [ [1, 2], [], [3], [4, 5], [] ]; | 
|  | assert(a.splitter(0).equal(w)); | 
|  | } | 
|  |  | 
|  | @safe unittest | 
|  | { | 
|  | import std.algorithm.iteration; | 
|  |  | 
|  | import std.algorithm.comparison : equal; | 
|  | import std.typecons : Yes; | 
|  |  | 
|  | assert("|ab|".splitter!("a == b", Yes.keepSeparators)('|') | 
|  | .equal([ "", "|", "ab", "|", "" ])); | 
|  | assert("ab".splitter!("a == b", Yes.keepSeparators)('|') | 
|  | .equal([ "ab" ])); | 
|  |  | 
|  | assert("a|b||c".splitter!("a == b", Yes.keepSeparators)('|') | 
|  | .equal([ "a", "|", "b", "|", "", "|", "c" ])); | 
|  | assert("hello  world".splitter!("a == b", Yes.keepSeparators)(' ') | 
|  | .equal([ "hello", " ", "", " ", "world" ])); | 
|  |  | 
|  | auto a = [ 1, 2, 0, 0, 3, 0, 4, 5, 0 ]; | 
|  | auto w = [ [1, 2], [0], [], [0], [3], [0], [4, 5], [0], [] ]; | 
|  | assert(a.splitter!("a == b", Yes.keepSeparators)(0).equal(w)); | 
|  | } | 
|  |  | 
|  | @safe unittest | 
|  | { | 
|  | import std.algorithm.iteration; | 
|  |  | 
|  | import std.algorithm.comparison : equal; | 
|  | import std.range : empty; | 
|  |  | 
|  | assert("".splitter('|').empty); | 
|  | assert("|".splitter('|').equal([ "", "" ])); | 
|  | assert("||".splitter('|').equal([ "", "", "" ])); | 
|  | } | 
|  |  | 
|  | @safe unittest | 
|  | { | 
|  | import std.algorithm.iteration; | 
|  |  | 
|  | import std.algorithm.comparison : equal; | 
|  | import std.typecons : Yes; | 
|  | import std.range : empty; | 
|  |  | 
|  | assert("".splitter!("a == b", Yes.keepSeparators)('|').empty); | 
|  | assert("|".splitter!("a == b", Yes.keepSeparators)('|') | 
|  | .equal([ "", "|", "" ])); | 
|  | assert("||".splitter!("a == b", Yes.keepSeparators)('|') | 
|  | .equal([ "", "|", "", "|", "" ])); | 
|  | } | 
|  |  | 
|  | @safe unittest | 
|  | { | 
|  | import std.algorithm.iteration; | 
|  |  | 
|  | import std.algorithm.comparison : equal; | 
|  |  | 
|  | assert("a=>bc=>def".splitter("=>").equal([ "a", "bc", "def" ])); | 
|  | assert("a|b||c".splitter("||").equal([ "a|b", "c" ])); | 
|  | assert("hello  world".splitter("  ").equal([ "hello", "world" ])); | 
|  |  | 
|  | int[] a = [ 1, 2, 0, 0, 3, 0, 4, 5, 0 ]; | 
|  | int[][] w = [ [1, 2], [3, 0, 4, 5, 0] ]; | 
|  | assert(a.splitter([0, 0]).equal(w)); | 
|  |  | 
|  | a = [ 0, 0 ]; | 
|  | assert(a.splitter([0, 0]).equal([ (int[]).init, (int[]).init ])); | 
|  |  | 
|  | a = [ 0, 0, 1 ]; | 
|  | assert(a.splitter([0, 0]).equal([ [], [1] ])); | 
|  | } | 
|  |  | 
|  | @safe unittest | 
|  | { | 
|  | import std.algorithm.iteration; | 
|  |  | 
|  | import std.algorithm.comparison : equal; | 
|  | import std.typecons : Yes; | 
|  |  | 
|  | assert("a=>bc=>def".splitter!("a == b", Yes.keepSeparators)("=>") | 
|  | .equal([ "a", "=>", "bc", "=>", "def" ])); | 
|  | assert("a|b||c".splitter!("a == b", Yes.keepSeparators)("||") | 
|  | .equal([ "a|b", "||", "c" ])); | 
|  | assert("hello  world".splitter!("a == b", Yes.keepSeparators)("  ") | 
|  | .equal([ "hello", "  ",  "world" ])); | 
|  |  | 
|  | int[] a = [ 1, 2, 0, 0, 3, 0, 4, 5, 0 ]; | 
|  | int[][] w = [ [1, 2], [0, 0], [3, 0, 4, 5, 0] ]; | 
|  | assert(a.splitter!("a == b", Yes.keepSeparators)([0, 0]).equal(w)); | 
|  |  | 
|  | a = [ 0, 0 ]; | 
|  | assert(a.splitter!("a == b", Yes.keepSeparators)([0, 0]) | 
|  | .equal([ (int[]).init, [0, 0], (int[]).init ])); | 
|  |  | 
|  | a = [ 0, 0, 1 ]; | 
|  | assert(a.splitter!("a == b", Yes.keepSeparators)([0, 0]) | 
|  | .equal([ [], [0, 0], [1] ])); | 
|  | } | 
|  |  | 
|  | @safe unittest | 
|  | { | 
|  | import std.algorithm.iteration; | 
|  |  | 
|  | import std.algorithm.comparison : equal; | 
|  | import std.ascii : toLower; | 
|  |  | 
|  | assert("abXcdxef".splitter!"a.toLower == b"('x').equal( | 
|  | [ "ab", "cd", "ef" ])); | 
|  |  | 
|  | auto w = [ [0], [1], [2] ]; | 
|  | assert(w.splitter!"a.front == b"(1).equal([ [[0]], [[2]] ])); | 
|  | } | 
|  |  | 
|  | @safe unittest | 
|  | { | 
|  | import std.algorithm.iteration; | 
|  |  | 
|  | import std.algorithm.comparison : equal; | 
|  | import std.typecons : Yes; | 
|  | import std.ascii : toLower; | 
|  |  | 
|  | assert("abXcdxef".splitter!("a.toLower == b", Yes.keepSeparators)('x') | 
|  | .equal([ "ab", "X", "cd", "x", "ef" ])); | 
|  |  | 
|  | auto w = [ [0], [1], [2] ]; | 
|  | assert(w.splitter!("a.front == b", Yes.keepSeparators)(1) | 
|  | .equal([ [[0]], [[1]], [[2]] ])); | 
|  | } | 
|  |  | 
|  | @safe unittest | 
|  | { | 
|  | import std.algorithm.iteration; | 
|  |  | 
|  | import std.algorithm.comparison : equal; | 
|  | import std.range.primitives : front; | 
|  |  | 
|  | assert(equal(splitter!(a => a == '|')("a|bc|def"), [ "a", "bc", "def" ])); | 
|  | 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]] ])); | 
|  | } | 
|  |  | 
|  | @safe unittest | 
|  | { | 
|  | import std.algorithm.iteration; | 
|  |  | 
|  | import std.algorithm.comparison : equal; | 
|  |  | 
|  | assert("|ab|".splitter('|').equal([ "", "ab", "" ])); | 
|  | assert("ab".splitter('|').equal([ "ab" ])); | 
|  | } | 
|  |  | 
|  | @safe unittest | 
|  | { | 
|  | import std.algorithm.iteration; | 
|  |  | 
|  | import std.algorithm.comparison : equal; | 
|  | import std.typecons : Yes; | 
|  |  | 
|  | assert("|ab|".splitter!("a == b", Yes.keepSeparators)('|') | 
|  | .equal([ "", "|", "ab", "|", "" ])); | 
|  | assert("ab".splitter!("a == b", Yes.keepSeparators)('|') | 
|  | .equal([ "ab" ])); | 
|  | } | 
|  |  | 
|  | @safe unittest | 
|  | { | 
|  | import std.algorithm.iteration; | 
|  |  | 
|  | import std.algorithm.comparison : equal; | 
|  | import std.range : retro; | 
|  | assert("a|bc|def".splitter('|').retro.equal([ "def", "bc", "a" ])); | 
|  | } | 
|  |  | 
|  | @safe unittest | 
|  | { | 
|  | import std.algorithm.iteration; | 
|  |  | 
|  | import std.algorithm.comparison : equal; | 
|  | import std.typecons : Yes; | 
|  | import std.range : retro; | 
|  | assert("a|bc|def".splitter!("a == b", Yes.keepSeparators)('|') | 
|  | .retro.equal([ "def", "|", "bc", "|", "a" ])); | 
|  | } | 
|  |  | 
|  | @safe unittest | 
|  | { | 
|  | import std.algorithm.iteration; | 
|  |  | 
|  | import std.ascii : isWhite; | 
|  | import std.algorithm.comparison : equal; | 
|  | import std.algorithm.iteration : splitter; | 
|  |  | 
|  | string str = "Hello World!"; | 
|  | assert(str.splitter!(isWhite).equal(["Hello", "World!"])); | 
|  | } | 
|  |  | 
|  | @safe pure unittest | 
|  | { | 
|  | import std.algorithm.iteration; | 
|  |  | 
|  | import std.algorithm.comparison : equal; | 
|  | auto a = " a     bcd   ef gh "; | 
|  | assert(equal(splitter(a), ["a", "bcd", "ef", "gh"][])); | 
|  | } | 
|  |  | 
|  | @safe pure unittest | 
|  | { | 
|  | import std.algorithm.iteration; | 
|  |  | 
|  | import std.algorithm.comparison : equal; | 
|  |  | 
|  | // substitute single elements | 
|  | assert("do_it".substitute('_', ' ').equal("do it")); | 
|  |  | 
|  | // substitute multiple, single elements | 
|  | assert("do_it".substitute('_', ' ', | 
|  | 'd', 'g', | 
|  | 'i', 't', | 
|  | 't', 'o') | 
|  | .equal("go to")); | 
|  |  | 
|  | // substitute subranges | 
|  | assert("do_it".substitute("_", " ", | 
|  | "do", "done") | 
|  | .equal("done it")); | 
|  |  | 
|  | // substitution works for any ElementType | 
|  | int[] x = [1, 2, 3]; | 
|  | auto y = x.substitute(1, 0.1); | 
|  | assert(y.equal([0.1, 2, 3])); | 
|  | static assert(is(typeof(y.front) == double)); | 
|  |  | 
|  | import std.range : retro; | 
|  | assert([1, 2, 3].substitute(1, 0.1).retro.equal([3, 2, 0.1])); | 
|  | } | 
|  |  | 
|  | @safe pure unittest | 
|  | { | 
|  | import std.algorithm.iteration; | 
|  |  | 
|  | import std.algorithm.comparison : equal; | 
|  |  | 
|  | // substitute subranges of a range | 
|  | assert("apple_tree".substitute!("apple", "banana", | 
|  | "tree", "shrub").equal("banana_shrub")); | 
|  |  | 
|  | // substitute subranges of a range | 
|  | assert("apple_tree".substitute!('a', 'b', | 
|  | 't', 'f').equal("bpple_free")); | 
|  |  | 
|  | // substitute values | 
|  | assert('a'.substitute!('a', 'b', 't', 'f') == 'b'); | 
|  | } | 
|  |  | 
|  | @safe pure unittest | 
|  | { | 
|  | import std.algorithm.iteration; | 
|  |  | 
|  | import std.algorithm.comparison : equal; | 
|  | import std.range.primitives : ElementType; | 
|  |  | 
|  | int[3] x = [1, 2, 3]; | 
|  | auto y = x[].substitute(1, 0.1) | 
|  | .substitute(0.1, 0.2); | 
|  | static assert(is(typeof(y.front) == double)); | 
|  | assert(y.equal([0.2, 2, 3])); | 
|  |  | 
|  | auto z = "42".substitute('2', '3') | 
|  | .substitute('3', '1'); | 
|  | static assert(is(ElementType!(typeof(z)) == dchar)); | 
|  | assert(equal(z, "41")); | 
|  | } | 
|  |  | 
|  | @safe pure nothrow unittest | 
|  | { | 
|  | import std.algorithm.iteration; | 
|  |  | 
|  | import std.range; | 
|  |  | 
|  | //simple integral sumation | 
|  | assert(sum([ 1, 2, 3, 4]) == 10); | 
|  |  | 
|  | //with integral promotion | 
|  | assert(sum([false, true, true, false, true]) == 3); | 
|  | assert(sum(ubyte.max.repeat(100)) == 25500); | 
|  |  | 
|  | //The result may overflow | 
|  | assert(uint.max.repeat(3).sum()           ==  4294967293U ); | 
|  | //But a seed can be used to change the sumation primitive | 
|  | assert(uint.max.repeat(3).sum(ulong.init) == 12884901885UL); | 
|  |  | 
|  | //Floating point sumation | 
|  | assert(sum([1.0, 2.0, 3.0, 4.0]) == 10); | 
|  |  | 
|  | //Floating point operations have double precision minimum | 
|  | static assert(is(typeof(sum([1F, 2F, 3F, 4F])) == double)); | 
|  | assert(sum([1F, 2, 3, 4]) == 10); | 
|  |  | 
|  | //Force pair-wise floating point sumation on large integers | 
|  | import std.math.operations : isClose; | 
|  | assert(iota(ulong.max / 2, ulong.max / 2 + 4096).sum(0.0) | 
|  | .isClose((ulong.max / 2) * 4096.0 + 4096^^2 / 2)); | 
|  | } | 
|  |  | 
|  | @safe @nogc pure nothrow unittest | 
|  | { | 
|  | import std.algorithm.iteration; | 
|  |  | 
|  | import std.math.operations : isClose; | 
|  | import std.math.traits : isNaN; | 
|  |  | 
|  | static immutable arr1 = [1, 2, 3]; | 
|  | static immutable arr2 = [1.5, 2.5, 12.5]; | 
|  |  | 
|  | assert(arr1.mean.isClose(2)); | 
|  | assert(arr2.mean.isClose(5.5)); | 
|  |  | 
|  | assert(arr1[0 .. 0].mean.isNaN); | 
|  | } | 
|  |  | 
|  | @safe unittest | 
|  | { | 
|  | import std.algorithm.iteration; | 
|  |  | 
|  | import std.algorithm.comparison : equal; | 
|  | import std.algorithm.mutation : copy; | 
|  |  | 
|  | 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])); | 
|  | } | 
|  |  | 
|  | @safe unittest | 
|  | { | 
|  | import std.algorithm.iteration; | 
|  |  | 
|  | 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]])); | 
|  | } | 
|  |  |