mirror of
https://github.com/dlang/tools.git
synced 2025-04-27 05:30:35 +03:00
642 lines
17 KiB
Text
642 lines
17 KiB
Text
# line 163
|
|
@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);
|
|
}
|
|
|
|
# line 218
|
|
@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.
|
|
}
|
|
|
|
# line 495
|
|
@safe unittest
|
|
{
|
|
import std.algorithm.iteration;
|
|
|
|
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 ]));
|
|
}
|
|
|
|
# line 510
|
|
@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;
|
|
}
|
|
}
|
|
|
|
# line 528
|
|
@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" ]));
|
|
}
|
|
|
|
# line 955
|
|
@system unittest
|
|
{
|
|
import std.algorithm.iteration;
|
|
|
|
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);
|
|
}
|
|
|
|
# line 1100
|
|
@safe unittest
|
|
{
|
|
import std.algorithm.iteration;
|
|
|
|
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 ]));
|
|
}
|
|
|
|
# line 1320
|
|
@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);
|
|
}
|
|
|
|
# line 1502
|
|
@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) ][]));
|
|
}
|
|
|
|
# line 1516
|
|
@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]);
|
|
}
|
|
|
|
# line 1907
|
|
@system 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]]
|
|
]));
|
|
}
|
|
|
|
# line 1957
|
|
@system 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();
|
|
}
|
|
}
|
|
|
|
# line 2280
|
|
@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"));
|
|
}
|
|
|
|
# line 2883
|
|
@safe unittest
|
|
{
|
|
import std.algorithm.iteration;
|
|
|
|
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));
|
|
}
|
|
|
|
# line 2938
|
|
@safe unittest
|
|
{
|
|
import std.algorithm.iteration;
|
|
|
|
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);
|
|
}
|
|
|
|
# line 3210
|
|
@safe pure unittest
|
|
{
|
|
import std.algorithm.iteration;
|
|
|
|
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);
|
|
|
|
// Return the last element of any range
|
|
assert(arr.fold!((a, b) => b) == 5);
|
|
}
|
|
|
|
# line 3418
|
|
@safe unittest
|
|
{
|
|
import std.algorithm.iteration;
|
|
|
|
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]));
|
|
}
|
|
|
|
# line 3474
|
|
@safe unittest
|
|
{
|
|
import std.algorithm.iteration;
|
|
|
|
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
|
|
}
|
|
|
|
# line 3831
|
|
@safe unittest
|
|
{
|
|
import std.algorithm.iteration;
|
|
|
|
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]] ]));
|
|
}
|
|
|
|
# line 4069
|
|
@safe unittest
|
|
{
|
|
import std.algorithm.iteration;
|
|
|
|
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] ]));
|
|
}
|
|
|
|
# line 4218
|
|
@safe unittest
|
|
{
|
|
import std.algorithm.iteration;
|
|
|
|
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]] ]));
|
|
}
|
|
|
|
# line 4507
|
|
@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"][]));
|
|
}
|
|
|
|
# line 4820
|
|
@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 : approxEqual;
|
|
assert(iota(ulong.max / 2, ulong.max / 2 + 4096).sum(0.0)
|
|
.approxEqual((ulong.max / 2) * 4096.0 + 4096^^2 / 2));
|
|
}
|
|
|
|
# line 4952
|
|
@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]));
|
|
}
|
|
|
|
# line 5178
|
|
@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]]));
|
|
}
|
|
|