| Function Name | Description |
|---|---|
| among | Checks if a value is among a set of values, e.g.if (v.among(1, 2, 3)) //v is 1, 2 or 3 |
| castSwitch | (new A()).castSwitch((A a)=>1,(B b)=>2) returns1. |
| clamp | clamp(1, 3, 6) returns3.clamp(4, 3, 6) returns4. |
| cmp | cmp("abc", "abcd") is-1,cmp("abc", "aba") is1, andcmp("abc", "abc") is0. |
| either | Return first parameterp that passes anif (p) test, e.g.either(0, 42, 43) returns42. |
| equal | Compares ranges for element-by-element equality, e.g.equal([1, 2, 3], [1.0, 2.0, 3.0]) returnstrue. |
| isPermutation | isPermutation([1, 2], [2, 1]) returnstrue. |
| isSameLength | isSameLength([1, 2, 3], [4, 5, 6]) returnstrue. |
| levenshteinDistance | levenshteinDistance("kitten", "sitting") returns3 by using the Levenshtein distance algorithm. |
| levenshteinDistanceAndPath | levenshteinDistanceAndPath("kitten", "sitting") returnstuple(3, "snnnsni") by using the Levenshtein distance algorithm. |
| max | max(3, 4, 2) returns4. |
| min | min(3, 4, 2) returns2. |
| mismatch | mismatch("oh hi", "ohayo") returnstuple(" hi", "ayo"). |
| predSwitch | 2.predSwitch(1, "one", 2, "two", 3, "three") returns"two". |
among(alias pred = (a, b) => a == b, Value, Values...)(Valuevalue, Valuesvalues)among(values...) if (isExpressionTuple!values)value amongvalues, returning the 1-based indexof the first matching value invalues, or0 ifvalueis not amongvalues. The predicatepred is used tocompare values, and uses equality by default.| pred | The predicate used to compare the values. |
Valuevalue | The value to search for. |
Valuesvalues | The values to compare the value to. |
assert(3.among(1, 42, 24, 3, 2));if (auto pos ="bar".among("foo","bar","baz")) writeln(pos);// 2elseassert(false);// 42 is larger than 24writeln(42.among!((lhs, rhs) => lhs > rhs)(43, 24, 100));// 2
values can be passed at compile-time, allowing for a moreefficient search, but one that only supports matching on equality:assert(3.among!(2, 3, 4));writeln("bar".among!("foo","bar","baz"));// 2
castSwitch(choices...)(ObjectswitchObject);switchObject can be casted to the typeof argument it accepts will be called withswitchObject casted to thattype, and the value it'll return will be returned bycastSwitch.If a choice's return type is void, the choice must throw an exception, unlessall the choices are void. In that case, castSwitch itself will return void.| choices | Thechoices needs to be composed of function or delegate handlers that accept one argument. There can also be a choice that accepts zero arguments. That choice will be invoked if the switchObject is null. |
ObjectswitchObject | the object against which the tests are being made. |
NotecastSwitch can only be used with object types.
import std.algorithm.iteration : map;import std.format : format;class A{int a;this(int a) {this.a = a;} @propertyint i() {return a; }}interface I { }class B : I { }Object[] arr = [new A(1),new B(),null];auto results = arr.map!(castSwitch!( (A a) =>"A with a value of %d".format(a.a), (I i) =>"derived from I", () =>"null reference", ))();// A is handled directly:writeln(results[0]);// "A with a value of 1"// B has no handler - it is handled by the handler of I:writeln(results[1]);// "derived from I"// null is handled by the null handler:writeln(results[2]);// "null reference"
import std.exception : assertThrown;class A { }class B { }// Void handlers are allowed if they throw:assertThrown!Exception(new B().castSwitch!( (A a) => 1, (B d) {thrownew Exception("B is not allowed!"); } )());// Void handlers are also allowed if all the handlers are void:new A().castSwitch!( (A a) { }, (B b) {assert(false); },)();
clamp(T1, T2, T3)(T1val, T2lower, T3upper);val into the given bounds. Result has the same type asval.T1val | The value to clamp. |
T2lower | The lower bound of the clamp. |
T3upper | The upper bound of the clamp. |
lower ifval is less thanlower,upper ifval is greater thanupper, andval in all other cases. Comparisons are made correctly (usingstd.functional.lessThan and the return value is converted to the return type using the standard integer coversion rulesstd.functional.greaterThan) even if the signedness ofT1,T2, andT3 are different.writeln(clamp(2, 1, 3));// 2writeln(clamp(0, 1, 3));// 1writeln(clamp(4, 1, 3));// 3writeln(clamp(1, 1, 1));// 1writeln(clamp(5, -1, 2u));// 2auto x =clamp(42,uint.max,uint.max);staticassert(is(typeof(x) ==int));writeln(x);// -1
cmp(R1, R2)(R1r1, R2r2)cmp(alias pred, R1, R2)(R1r1, R2r2)r1 andr2 in lockstep,cmp compares each elemente1 ofr1 with the corresponding elemente2 inr2. If oneof the ranges has been finished,cmp returns a negative valueifr1 has fewer elements thanr2, a positive value ifr1has more elements thanr2, and0 if the ranges have the samenumber of elements.cmp performs UTF decodingappropriately and compares the ranges one code point at a time.A custom predicate may be specified, in which casecmp performsa three-way lexicographical comparison usingpred. Otherwisethe elements are compared usingopCmp.| pred | Predicate used for comparison. Without a predicate specified the ordering implied byopCmp is used. |
R1r1 | The first range. |
R2r2 | The second range. |
r1 is a prefix ofr2 or the first differing element ofr1 is less than the corresponding element ofr2 according topred. A positive value ifr2 is a prefix ofr1 or the first differing element ofr2 is less than the corresponding element ofr1 according topred.NoteAn earlier version of the documentation incorrectly stated that-1 is the only negative value returned and1 is the only positive value returned. Whether that is true depends on the types being compared.
int result;result =cmp("abc","abc");writeln(result);// 0result =cmp("","");writeln(result);// 0result =cmp("abc","abcd");assert(result < 0);result =cmp("abcd","abc");assert(result > 0);result =cmp("abc"d,"abd");assert(result < 0);result =cmp("bbc","abc"w);assert(result > 0);result =cmp("aaa","aaaa"d);assert(result < 0);result =cmp("aaaa","aaa"d);assert(result > 0);result =cmp("aaa","aaa"d);writeln(result);// 0result =cmp("aaa"d,"aaa"d);writeln(result);// 0result =cmp(cast(int[])[],cast(int[])[]);writeln(result);// 0result =cmp([1, 2, 3], [1, 2, 3]);writeln(result);// 0result =cmp([1, 3, 2], [1, 2, 3]);assert(result > 0);result =cmp([1, 2, 3], [1L, 2, 3, 4]);assert(result < 0);result =cmp([1L, 2, 3], [1, 2]);assert(result > 0);
int result;result =cmp!"a > b"("abc","abc");writeln(result);// 0result =cmp!"a > b"("","");writeln(result);// 0result =cmp!"a > b"("abc","abcd");assert(result < 0);result =cmp!"a > b"("abcd","abc");assert(result > 0);result =cmp!"a > b"("abc"d,"abd");assert(result > 0);result =cmp!"a > b"("bbc","abc"w);assert(result < 0);result =cmp!"a > b"("aaa","aaaa"d);assert(result < 0);result =cmp!"a > b"("aaaa","aaa"d);assert(result > 0);result =cmp!"a > b"("aaa","aaa"d);writeln(result);// 0result =cmp("aaa"d,"aaa"d);writeln(result);// 0result =cmp!"a > b"(cast(int[])[],cast(int[])[]);writeln(result);// 0result =cmp!"a > b"([1, 2, 3], [1, 2, 3]);writeln(result);// 0result =cmp!"a > b"([1, 3, 2], [1, 2, 3]);assert(result < 0);result =cmp!"a > b"([1, 2, 3], [1L, 2, 3, 4]);assert(result < 0);result =cmp!"a > b"([1L, 2, 3], [1, 2]);assert(result > 0);
equal(alias pred = "a == b")import std.algorithm.comparison :equal;import std.math.operations : isClose;int[4] a = [ 1, 2, 4, 3 ];assert(!equal(a[], a[1..$]));assert(equal(a[], a[]));assert(equal!((a, b) => a == b)(a[], a[]));// different typesdouble[4] b = [ 1.0, 2, 4, 3];assert(!equal(a[], b[1..$]));assert(equal(a[], b[]));// predicated: ensure that two vectors are approximately equaldouble[4] c = [ 1.0000000005, 2, 4, 3];assert(equal!isClose(b[], c[]));
equal can itself be used as a predicate to other functions.This can be very useful when the element type of a range is itself arange. In particular,equal can be its own predicate, allowingrange of range (of range...) comparisons.import std.algorithm.comparison :equal;import std.range : iota, chunks;assert(equal!(equal!equal)( [[[0, 1], [2, 3]], [[4, 5], [6, 7]]], iota(0, 8).chunks(2).chunks(2)));
equal(Ranges...)(Rangesrs)rs.length > 1 && allSatisfy!(isInputRange, Ranges) && !allSatisfy!(isInfinite, Ranges) && is(typeof(binaryFun!pred(rs[0].front,rs[1].front))) && (rs.length == 2 || is(typeof(equal!pred(rs[1..$])) == bool)));equal is invoked with the default predicate, the implementation may take the liberty to use faster implementations that have the theoretical worst-caseΟ(max(rs[0].length, rs[1].length, ...)).Rangesrs | The ranges to be compared. |
EditOp: char;EditOp encodes the steps that need to be taken toconverts intot. For example, ifs = "cat" and"cars", the minimal sequence that transformss intot is:skip two characters, replace 't' with 'r', and insert an 's'. Workingwith edit operations is useful in applications such as spell-checkers(to find the closest word to a given misspelled word), approximatesearches, diff-style programs that compute the difference betweenfiles, efficient encoding of patches, DNA sequence analysis, andplagiarism detection.with(EditOp){// [none, none, none, insert, insert, insert] writeln(levenshteinDistanceAndPath("foo","foobar")[1]);// [substitute, none, substitute, none, none, remove] writeln(levenshteinDistanceAndPath("banana","fazan")[1]);}
nonesubstituteinsertremovelevenshteinDistance(alias equals = (a, b) => a == b, Range1, Range2)(Range1s, Range2t)levenshteinDistance(alias equals = (a, b) => a == b, Range1, Range2)(auto ref Range1s, auto ref Range2t)s andt. The Levenshtein distance computesthe minimal amount of edit operations necessary to transformsintot. PerformsΟ(s.length * t.length) evaluations ofequals and occupiesΟ(min(s.length, t.length)) storage.| equals | The binary predicate to compare the elements of the two ranges. |
Range1s | The original range. |
Range2t | The transformation target |
import std.algorithm.iteration : filter;import std.uni : toUpper;writeln(levenshteinDistance("cat","rat"));// 1writeln(levenshteinDistance("parks","spark"));// 2writeln(levenshteinDistance("abcde","abcde"));// 0writeln(levenshteinDistance("abcde","abCde"));// 1writeln(levenshteinDistance("kitten","sitting"));// 3assert(levenshteinDistance!((a, b) => toUpper(a) == toUpper(b)) ("parks","SPARK") == 2);writeln(levenshteinDistance("parks".filter!"true","spark".filter!"true"));// 2writeln(levenshteinDistance("ID","I♥D"));// 1
levenshteinDistanceAndPath(alias equals = (a, b) => a == b, Range1, Range2)(Range1s, Range2t)levenshteinDistanceAndPath(alias equals = (a, b) => a == b, Range1, Range2)(auto ref Range1s, auto ref Range2t)s andt.| equals | The binary predicate to compare the elements of the two ranges. |
Range1s | The original range. |
Range2t | The transformation target |
string a ="Saturday", b ="Sundays";auto p =levenshteinDistanceAndPath(a, b);writeln(p[0]);// 4assert(equal(p[1],"nrrnsnnni"));
max(T...)(Targs)max(T, U)(Ta, Ub)a <b)));Targs | The values to select the maximum from. At least two arguments must be passed, and they must be comparable with<. |
inta = 5;shortb = 6;double c = 2;auto d =max(a,b);assert(is(typeof(d) ==int));writeln(d);// 6auto e = min(a,b, c);assert(is(typeof(e) ==double));writeln(e);// 2
min(T...)(Targs)min(T, U)(Ta, Ub)a <b)));Targs | The values to select the minimum from. At least two arguments must be passed, and they must be comparable with<. |
inta = 5;shortb = 6;double c = 2;auto d =min(a,b);staticassert(is(typeof(d) ==int));writeln(d);// 5auto e =min(a,b, c);staticassert(is(typeof(e) ==double));writeln(e);// 2ulong f = 0xffff_ffff_ffff;constuint g =min(f, 0xffff_0000);writeln(g);// 0xffff_0000dchar h = 100;uint i = 101;staticassert(is(typeof(min(h, i)) ==dchar));staticassert(is(typeof(min(i, h)) ==uint));writeln(min(h, i));// 100
inta = -10;uint f = 10;staticassert(is(typeof(min(a, f)) ==int));writeln(min(a, f));// -10
import std.datetime;writeln(min(Date(2012, 12, 21), Date(1982, 1, 4)));// Date(1982, 1, 4)writeln(min(Date(1982, 1, 4), Date(2012, 12, 21)));// Date(1982, 1, 4)writeln(min(Date(1982, 1, 4), Date.min));// Date.minwriteln(min(Date.min, Date(1982, 1, 4)));// Date.minwriteln(min(Date(1982, 1, 4), Date.max));// Date(1982, 1, 4)writeln(min(Date.max, Date(1982, 1, 4)));// Date(1982, 1, 4)writeln(min(Date.min, Date.max));// Date.minwriteln(min(Date.max, Date.min));// Date.min
mismatch(alias pred = (a, b) => a == b, Ranges...)(Rangesrs)rs.length >= 2 && allSatisfy!(isInputRange, Ranges));rs in lockstep, andstops at the first mismatch (according topred, by defaultequality). Returns a tuple with the reduced ranges that start with thetwo mismatched values. PerformsΟ(min(r[0].length, r[1].length, ...))evaluations ofpred.int[6] x = [ 1, 5, 2, 7, 4, 3 ];double[6] y = [ 1.0, 5, 2, 7.3, 4, 8 ];auto m =mismatch(x[], y[]);writeln(m[0]);// x[3 .. $]writeln(m[1]);// y[3 .. $]auto m2 =mismatch(x[], y[], x[], y[]);writeln(m2[0]);// x[3 .. $]writeln(m2[1]);// y[3 .. $]writeln(m2[2]);// x[3 .. $]writeln(m2[3]);// y[3 .. $]
predSwitch(alias pred = "a == b", T, R...)(TswitchExpression, lazy Rchoices);choices needs to be composed of pairs of test expressions and returnexpressions. Each test-expression is compared withswitchExpression usingpred(switchExpression is the first argument) and if that yields true -the return expression is returned.Both the test and the return expressions are lazily evaluated.TswitchExpression | The first argument for the predicate. |
Rchoices | Pairs of test expressions and return expressions. The testexpressions will be the second argument for the predicate, and the returnexpression will be returned if the predicate yields true withswitchExpression and the test expression as arguments. May also have adefault return expression, that needs to be the last expression without a testexpression before it. A return expression may be of void type only if italways throws. |
string res = 2.predSwitch!"a < b"( 1,"less than 1", 5,"less than 5", 10,"less than 10","greater or equal to 10");writeln(res);// "less than 5"//The arguments are lazy, which allows us to use predSwitch to create//recursive functions:int factorial(int n){return n.predSwitch!"a <= b"( -1, {thrownew Exception("Can not calculate n! for n < 0");}(), 0, 1,// 0! = 1 n * factorial(n - 1)// n! = n * (n - 1)! for n >= 0 );}writeln(factorial(3));// 6//Void return expressions are allowed if they always throw:import std.exception : assertThrown;assertThrown!Exception(factorial(-9));
isSameLength(Ranges...)(Rangesrs)Rangesrs | two or moreinput ranges |
assert(isSameLength([1, 2, 3], [4, 5, 6]));assert(isSameLength([1, 2, 3], [4, 5, 6], [7, 8, 9]));assert(isSameLength([0.3, 90.4, 23.7, 119.2], [42.6, 23.6, 95.5, 6.3]));assert(isSameLength("abc","xyz"));assert(isSameLength("abc","xyz", [1, 2, 3]));int[] a;int[] b;assert(isSameLength(a, b));assert(isSameLength(a, b, a, a, b, b, b));assert(!isSameLength([1, 2, 3], [4, 5]));assert(!isSameLength([1, 2, 3], [4, 5, 6], [7, 8]));assert(!isSameLength([0.3, 90.4, 23.7], [42.6, 23.6, 95.5, 6.3]));assert(!isSameLength("abcd","xyz"));assert(!isSameLength("abcd","xyz","123"));assert(!isSameLength("abcd","xyz","1234"));
isPermutation(Flag!"allocateGC" allocateGC, Range1, Range2)(Range1r1, Range2r2)isPermutation(alias pred = "a == b", Range1, Range2)(Range1r1, Range2r2)| pred | an optional parameter to change how equality is defined |
| allocateGC | Yes.allocateGC/No.allocateGC |
Range1r1 | A finiteforward range |
Range2r2 | A finiteforward range |
r1 appear the same number of times inr2. Otherwise, returnsfalse.import std.typecons : Yes;assert(isPermutation([1, 2, 3], [3, 2, 1]));assert(isPermutation([1.1, 2.3, 3.5], [2.3, 3.5, 1.1]));assert(isPermutation("abc","bca"));assert(!isPermutation([1, 2], [3, 4]));assert(!isPermutation([1, 1, 2, 3], [1, 2, 2, 3]));assert(!isPermutation([1, 1], [1, 1, 1]));// Faster, but allocates GC handled memoryassert(isPermutation!(Yes.allocateGC)([1.1, 2.3, 3.5], [2.3, 3.5, 1.1]));assert(!isPermutation!(Yes.allocateGC)([1, 2], [3, 4]));
either(alias pred = (a) => a, T, Ts...)(Tfirst, lazy Tsalternatives)alternatives.length >= 1 && !is(CommonType!(T, Ts) == void) && allSatisfy!(ifTestable, T, Ts));either asnothrow. See issue atBugzilla 12647.const a = 1;const b = 2;auto ab =either(a, b);staticassert(is(typeof(ab) ==const(int)));writeln(ab);// aauto c = 2;const d = 3;auto cd =either!(a => a == 3)(c, d);// use predicatestaticassert(is(typeof(cd) ==int));writeln(cd);// dauto e = 0;const f = 2;auto ef =either(e, f);staticassert(is(typeof(ef) ==int));writeln(ef);// f
immutable p = 1;immutable q = 2;auto pq =either(p, q);staticassert(is(typeof(pq) ==immutable(int)));writeln(pq);// pwriteln(either(3, 4));// 3writeln(either(0, 4));// 4writeln(either(0, 0));// 0writeln(either("","a"));// ""
string r =null;writeln(either(r,"a"));// "a"writeln(either("a",""));// "a"immutable s = [1, 2];writeln(either(s, s));// swriteln(either([0, 1], [1, 2]));// [0, 1]writeln(either([0, 1], [1]));// [0, 1]writeln(either("a","b"));// "a"staticassert(!__traits(compiles,either(1,"a")));staticassert(!__traits(compiles,either(1.0,"a")));staticassert(!__traits(compiles,either('a',"a")));