This module defines the notion of a range
. Ranges generalize the concept of arrays, lists, or anything that involves sequential access. This abstraction enables the same set of algorithms (see std.algorithm
) to be used with a vast variety of different concrete types. For example, a linear search algorithm such as std.algorithm.searching.find
works not just for arrays, but for linkedlists, input files, incoming network data, etc.
range
based code.std.range.primitives
submodule provides basic range functionality. It defines several templates for testing whether a given object is a range, what kind of range it is, and provides some common range operations. The std.range.interfaces
submodule provides objectbased interfaces for working with ranges via runtime polymorphism. The remainder of this module provides a rich set of range creation and composition templates that let you construct new ranges out of existing ranges: chain  Concatenates several ranges into a single range. 
choose  Chooses one of two ranges at runtime based on a boolean condition. 
chooseAmong  Chooses one of several ranges at runtime based on an index. 
chunks  Creates a range that returns fixedsize chunks of the original range. 
cycle  Creates an infinite range that repeats the given forward range indefinitely. Good for implementing circular buffers. 
drop  Creates the range that results from discarding the first n elements from the given range. 
dropBack  Creates the range that results from discarding the last n elements from the given range. 
dropExactly  Creates the range that results from discarding exactly n of the first elements from the given range. 
dropBackExactly  Creates the range that results from discarding exactly n of the last elements from the given range. 
dropOne  Creates the range that results from discarding the first element from the given range. 
dropBackOne  Creates the range that results from discarding the last element from the given range. 
enumerate  Iterates a range with an attached index variable. 
evenChunks  Creates a range that returns a number of chunks of approximately equal length from the original range. 
frontTransversal  Creates a range that iterates over the first elements of the given ranges. 
generate  Creates a range by successive calls to a given function. This allows to create ranges as a single delegate. 
indexed  Creates a range that offers a view of a given range as though its elements were reordered according to a given range of indices. 
iota  Creates a range consisting of numbers between a starting point and ending point, spaced apart by a given interval. 
lockstep  Iterates n ranges in lockstep, for use in a foreach loop. Similar to zip , except that lockstep is designed especially for foreach loops. 
NullSink  An output range that discards the data it receives. 
only  Creates a range that iterates over the given arguments. 
padLeft  Pads a range to a specified length by adding a given element to the front of the range. Is lazy if the range has a known length. 
padRight  Lazily pads a range to a specified length by adding a given element to the back of the range. 
radial  Given a randomaccess range and a starting point, creates a range that alternately returns the next left and next right element to the starting point. 
recurrence  Creates a forward range whose values are defined by a mathematical recurrence relation. 
refRange  Pass a range by reference. Both the original range and the RefRange will always have the exact same elements. Any operation done on one will affect the other. 
repeat  Creates a range that consists of a single element repeated n times, or an infinite range repeating that element indefinitely. 
retro  Iterates a bidirectional range backwards. 
roundRobin  Given n ranges, creates a new range that return the n first elements of each range, in turn, then the second element of each range, and so on, in a roundrobin fashion. 
sequence  Similar to recurrence , except that a randomaccess range is created. 
stride  Iterates a range with stride n. 
tail  Return a range advanced to within n elements of the end of the given range. 
take  Creates a subrange consisting of only up to the first n elements of the given range. 
takeExactly  Like take , but assumes the given range actually has n elements, and therefore also defines the length property. 
takeNone  Creates a randomaccess range consisting of zero elements of the given range. 
takeOne  Creates a randomaccess range consisting of exactly the first element of the given range. 
tee  Creates a range that wraps a given range, forwarding along its elements while also calling a provided function with each element. 
transposed  Transposes a range of ranges. 
transversal  Creates a range that iterates over the n'th elements of the given randomaccess ranges. 
zip  Given n ranges, creates a range that successively returns a tuple of all the first elements, a tuple of all the second elements, etc. 
assumeSorted
function can be used to construct a SortedRange
from a presorted range. The std.algorithm.sorting.sort
function also conveniently returns a SortedRange
. SortedRange
objects provide some additional range operations that take advantage of the fact that the range is sorted. Iterates a bidirectional range backwards. The original range can be accessed by using the source
property. Applying retro
twice to the same range yields the original range.
Range r
 the bidirectional range to iterate backwards 
r
also provides a length. Or, if r
is a random access range, then the return value will be random access as well. std.algorithm.mutation.reverse
for mutating the source range directly.import std.algorithm.comparison : equal; int[5] a = [ 1, 2, 3, 4, 5 ]; int[5] b = [ 5, 4, 3, 2, 1 ]; assert(equal(retro(a[]), b[])); assert(retro(a[]).source is a[]); assert(retro(retro(a[])) is a[]);
Iterates range r
with stride
n
. If the range is a randomaccess range, moves by indexing into the range; otherwise, moves by successive calls to popFront
. Applying stride
twice to the same range results in a stride
with a step that is the product of the two applications. It is an error for n
to be 0.
Range r
 the input range to stride over 
size_t n
 the number of elements to skip over 
std.range.primitives.hasLength
is true
.import std.algorithm.comparison : equal; int[] a = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 ]; assert(equal(stride(a, 3), [ 1, 4, 7, 10 ][])); writeln(stride(stride(a, 2), 3)); // stride(a, 6)
Spans multiple ranges in sequence. The function chain
takes any number of ranges and returns a Chain!(R1, R2,...)
object. The ranges may be different, but they must have the same element type. The result is a range that offers the front
, popFront
, and empty
primitives. If all input ranges offer random access and length
, Chain
offers them as well.
If only one range is offered to Chain
or chain
, the Chain
type exits the picture by aliasing itself directly to that range's type.
Ranges rs
 the input ranges to chain together 
rs
provide a range primitive, the returned range will also provide that range primitive. only
to chain
values to a rangeimport std.algorithm.comparison : equal; int[] arr1 = [ 1, 2, 3, 4 ]; int[] arr2 = [ 5, 6 ]; int[] arr3 = [ 7 ]; auto s = chain(arr1, arr2, arr3); writeln(s.length); // 7 writeln(s[5]); // 6 assert(equal(s, [1, 2, 3, 4, 5, 6, 7][]));
import std.algorithm.comparison : equal; import std.algorithm.sorting : sort; int[] arr1 = [5, 2, 8]; int[] arr2 = [3, 7, 9]; int[] arr3 = [1, 4, 6]; // inplace sorting across all of the arrays auto s = arr1.chain(arr2, arr3).sort; assert(s.equal([1, 2, 3, 4, 5, 6, 7, 8, 9])); assert(arr1.equal([1, 2, 3])); assert(arr2.equal([4, 5, 6])); assert(arr3.equal([7, 8, 9]));
Choose one of two ranges at runtime depending on a Boolean condition
.
The ranges may be different, but they must have compatible element types (i.e. CommonType
must exist for the two element types). The result is a range that offers the weakest capabilities of the two (e.g. ForwardRange
if R1
is a randomaccess range and R2
is a forward range).
bool condition
 which range to choose : r1 if true , r2 otherwise 
R1 r1
 the "true " range 
R2 r2
 the "false " range 
R1
and R2
. import std.algorithm.comparison : equal; import std.algorithm.iteration : filter, map; auto data1 = [ 1, 2, 3, 4 ].filter!(a => a != 3); auto data2 = [ 5, 6, 7, 8 ].map!(a => a + 1); // choose() is primarily useful when you need to select one of two ranges // with different types at runtime. static assert(!is(typeof(data1) == typeof(data2))); auto chooseRange(bool pickFirst) { // The returned range is a common wrapper type that can be used for // returning or storing either range without running into a type error. return choose(pickFirst, data1, data2); // Simply returning the chosen range without using choose() does not // work, because map() and filter() return different types. //return pickFirst ? data1 : data2; // does not compile } auto result = chooseRange(true); assert(result.equal([ 1, 2, 4 ])); result = chooseRange(false); assert(result.equal([ 6, 7, 8, 9 ]));
Choose one of multiple ranges at runtime.
The ranges may be different, but they must have compatible element types. The result is a range that offers the weakest capabilities of all Ranges
.
size_t index
 which range to choose, must be less than the number of ranges 
Ranges rs
 two or more ranges 
rs
consists of only one range, the return type is an alias of that range's type.import std.algorithm.comparison : equal; int[] arr1 = [ 1, 2, 3, 4 ]; int[] arr2 = [ 5, 6 ]; int[] arr3 = [ 7 ]; { auto s = chooseAmong(0, arr1, arr2, arr3); auto t = s.save; writeln(s.length); // 4 writeln(s[2]); // 3 s.popFront(); assert(equal(t, [1, 2, 3, 4][])); } { auto s = chooseAmong(1, arr1, arr2, arr3); writeln(s.length); // 2 s.front = 8; assert(equal(s, [8, 6][])); } { auto s = chooseAmong(1, arr1, arr2, arr3); writeln(s.length); // 2 s[1] = 9; assert(equal(s, [8, 9][])); } { auto s = chooseAmong(1, arr2, arr1, arr3)[1 .. 3]; writeln(s.length); // 2 assert(equal(s, [2, 3][])); } { auto s = chooseAmong(0, arr1, arr2, arr3); writeln(s.length); // 4 writeln(s.back); // 4 s.popBack(); s.back = 5; assert(equal(s, [1, 2, 5][])); s.back = 3; assert(equal(s, [1, 2, 3][])); } { uint[] foo = [1,2,3,4,5]; uint[] bar = [6,7,8,9,10]; auto c = chooseAmong(1,foo, bar); writeln(c[3]); // 9 c[3] = 42; writeln(c[3]); // 42 writeln(c.moveFront()); // 6 writeln(c.moveBack()); // 10 writeln(c.moveAt(4)); // 10 } { import std.range : cycle; auto s = chooseAmong(1, cycle(arr2), cycle(arr3)); assert(isInfinite!(typeof(s))); assert(!s.empty); writeln(s[100]); // 7 }
roundRobin(r1, r2, r3)
yields r1.front
, then r2.front
, then r3.front
, after which it pops off one element from each and continues again from r1
. For example, if two ranges are involved, it alternately yields elements off the two ranges. roundRobin
stops after it has consumed all ranges (skipping over the ones that finish early).
import std.algorithm.comparison : equal; int[] a = [ 1, 2, 3 ]; int[] b = [ 10, 20, 30, 40 ]; auto r = roundRobin(a, b); assert(equal(r, [ 1, 10, 2, 20, 3, 30, 40 ]));
roundRobin
can be used to create "interleave" functionality which inserts an element between each element in a range. import std.algorithm.comparison : equal; auto interleave(R, E)(R range, E element) if ((isInputRange!R && hasLength!R)  isForwardRange!R) { static if (hasLength!R) immutable len = range.length; else immutable len = range.save.walkLength; return roundRobin( range, element.repeat(len  1) ); } assert(interleave([1, 2, 3], 0).equal([1, 0, 2, 0, 3]));
Iterates a randomaccess range starting from a given point and progressively extending left and right from that point. If no initial point is given, iteration starts from the middle of the range. Iteration spans the entire range.
When startingIndex
is 0 the range will be fully iterated in order and in reverse order when r.length
is given.
Range r
 a random access range with length and slicing 
I startingIndex
 the index to begin iteration from 
import std.algorithm.comparison : equal; int[] a = [ 1, 2, 3, 4, 5 ]; assert(equal(radial(a), [ 3, 4, 2, 5, 1 ])); a = [ 1, 2, 3, 4 ]; assert(equal(radial(a), [ 2, 3, 1, 4 ])); // If the left end is reached first, the remaining elements on the right // are concatenated in order: a = [ 0, 1, 2, 3, 4, 5 ]; assert(equal(radial(a, 1), [ 1, 2, 0, 3, 4, 5 ])); // If the right end is reached first, the remaining elements on the left // are concatenated in reverse order: assert(equal(radial(a, 4), [ 4, 5, 3, 2, 1, 0 ]));
Lazily takes only up to n
elements of a range. This is particularly useful when using with infinite ranges.
Unlike takeExactly
, take
does not require that there are n
or more elements in input
. As a consequence, length information is not applied to the result unless input
also has length information.
R input
 an input range to iterate over up to n times 
size_t n
 the number of elements to take

input
range. If the range offers random access and length
, take
offers them as well.This template simply aliases itself to R and is useful for consistency in generic code.
import std.algorithm.comparison : equal; int[] arr1 = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ]; auto s = take(arr1, 5); writeln(s.length); // 5 writeln(s[4]); // 5 assert(equal(s, [ 1, 2, 3, 4, 5 ][]));
n
elements, take
simply returns the entire range (unlike takeExactly
, which will cause an assertion failure if the range ends prematurely): import std.algorithm.comparison : equal; int[] arr2 = [ 1, 2, 3 ]; auto t = take(arr2, 5); writeln(t.length); // 3 assert(equal(t, [ 1, 2, 3 ]));
Similar to take
, but assumes that range
has at least n
elements. Consequently, the result of takeExactly(range, n)
always defines the length
property (and initializes it to n
) even when range
itself does not define length
.
The result of takeExactly
is identical to that of take
in cases where the original range
defines length
or is infinite.
Unlike take
, however, it is illegal to pass a range
with less than n
elements to takeExactly
; this will cause an assertion failure.
import std.algorithm.comparison : equal; auto a = [ 1, 2, 3, 4, 5 ]; auto b = takeExactly(a, 3); assert(equal(b, [1, 2, 3])); static assert(is(typeof(b.length) == size_t)); writeln(b.length); // 3 writeln(b.front); // 1 writeln(b.back); // 3
Returns a range with at most one element; for example, takeOne([42, 43, 44])
returns a range consisting of the integer 42
. Calling popFront()
off that range renders it empty.
In effect takeOne(r)
is somewhat equivalent to take(r, 1)
but in certain interfaces it is important to know statically that the range may only have at most one element.
The type returned by takeOne
is a randomaccess range with length regardless of R
's capabilities, as long as it is a forward range. (another feature that distinguishes takeOne
from take
). If (D R) is an input range but not a forward range, return type is an input range with all randomaccess capabilities except save.
auto s = takeOne([42, 43, 44]); static assert(isRandomAccessRange!(typeof(s))); writeln(s.length); // 1 assert(!s.empty); writeln(s.front); // 42 s.front = 43; writeln(s.front); // 43 writeln(s.back); // 43 writeln(s[0]); // 43 s.popFront(); writeln(s.length); // 0 assert(s.empty);
Returns an empty range which is statically known to be empty and is guaranteed to have length
and be random access regardless of R
's capabilities.
auto range = takeNone!(int[])(); writeln(range.length); // 0 assert(range.empty);
Creates an empty range
from the given range
in Ο(1
). If it can, it will return the same range
type. If not, it will return takeExactly(range, 0)
.
import std.algorithm.iteration : filter; assert(takeNone([42, 27, 19]).empty); assert(takeNone("dlang.org").empty); assert(takeNone(filter!"true"([42, 27, 19])).empty);
Return a range advanced to within n
elements of the end of range
.
Intended as the range equivalent of the Unix tail utility. When the length of range
is less than or equal to n
, range
is returned asis.
Completes in Ο(1
) steps for ranges that support slicing and have length. Completes in Ο(range.length
) time for all other ranges.
Range range
 range to get tail of 
size_t n
 maximum number of elements to include in tail 
range
augmented with length information// tail c n writeln([1, 2, 3].tail(1)); // [3] writeln([1, 2, 3].tail(2)); // [2, 3] writeln([1, 2, 3].tail(3)); // [1, 2, 3] writeln([1, 2, 3].tail(4)); // [1, 2, 3] writeln([1, 2, 3].tail(0).length); // 0 // tail lines=n import std.algorithm.comparison : equal; import std.algorithm.iteration : joiner; import std.exception : assumeWontThrow; import std.string : lineSplitter; assert("one\ntwo\nthree" .lineSplitter .tail(2) .joiner("\n") .equal("two\nthree") .assumeWontThrow);
Convenience function which calls std.range.primitives.popFrontN
(range, n)
and returns range
. drop
makes it easier to pop elements from a range
and then pass it to another function within a single expression, whereas popFrontN
would require multiple statements.
dropBack
provides the same functionality but instead calls std.range.primitives.popBackN
(range, n)
drop
and dropBack
will only pop up to n
elements but will stop if the range
is empty first. In other languages this is sometimes called skip
. R range
 the input range to drop from 
size_t n
 the number of elements to drop

range
with up to n
elements dropped import std.algorithm.comparison : equal; writeln([0, 2, 1, 5, 0, 3].drop(3)); // [5, 0, 3] writeln("hello world".drop(6)); // "world" assert("hello world".drop(50).empty); assert("hello world".take(6).drop(3).equal("lo "));
Similar to drop
and dropBack
but they call range.popFrontExactly(n)
and range.popBackExactly(n)
instead.
drop
, dropExactly
will assume that the range
holds at least n
elements. This makes dropExactly
faster than drop
, but it also means that if range
does not contain at least n
elements, it will attempt to call popFront
on an empty range
, which is undefined behavior. So, only use popFrontExactly
when it is guaranteed that range
holds at least n
elements. R range
 the input range to drop from 
size_t n
 the number of elements to drop 
range
with n
elements dropped import std.algorithm.comparison : equal; import std.algorithm.iteration : filterBidirectional; auto a = [1, 2, 3]; writeln(a.dropExactly(2)); // [3] writeln(a.dropBackExactly(2)); // [1] string s = "日本語"; writeln(s.dropExactly(2)); // "語" writeln(s.dropBackExactly(2)); // "日" auto bd = filterBidirectional!"true"([1, 2, 3]); assert(bd.dropExactly(2).equal([3])); assert(bd.dropBackExactly(2).equal([1]));
Convenience function which calls range.popFront()
and returns range
. dropOne
makes it easier to pop an element from a range
and then pass it to another function within a single expression, whereas popFront
would require multiple statements.
dropBackOne
provides the same functionality but instead calls range.popBack()
.
import std.algorithm.comparison : equal; import std.algorithm.iteration : filterBidirectional; import std.container.dlist : DList; auto dl = DList!int(9, 1, 2, 3, 9); assert(dl[].dropOne().dropBackOne().equal([1, 2, 3])); auto a = [1, 2, 3]; writeln(a.dropOne()); // [2, 3] writeln(a.dropBackOne()); // [1, 2] string s = "日本語"; import std.exception : assumeWontThrow; assert(assumeWontThrow(s.dropOne() == "本語")); assert(assumeWontThrow(s.dropBackOne() == "日本")); auto bd = filterBidirectional!"true"([1, 2, 3]); assert(bd.dropOne().equal([2, 3])); assert(bd.dropBackOne().equal([1, 2]));
Create a range which repeats one value
forever.
T value
 the value to repeat

import std.algorithm.comparison : equal; assert(equal(5.repeat().take(4), [ 5, 5, 5, 5 ]));
Range primitives
Repeats value
exactly n
times. Equivalent to take(repeat(value), n)
.
import std.algorithm.comparison : equal; assert(equal(5.repeat(4), 5.repeat().take(4)));
Given callable (std.traits.isCallable
) fun
, create as a range whose front is defined by successive calls to fun()
. This is especially useful to call function with global side effects (random functions), or to create ranges expressed as a single delegate, rather than an entire front
/popFront
/empty
structure. fun
maybe be passed either a template alias parameter (existing function, delegate, struct type defining static opCall
) or a runtime value argument (delegate, function object). The result range models an InputRange (std.range.primitives.isInputRange
). The resulting range will call fun()
on construction, and every call to popFront
, and the cached value will be returned when front
is called.
inputRange
where each element represents another call to fun
.import std.algorithm.comparison : equal; import std.algorithm.iteration : map; int i = 1; auto powersOfTwo = generate!(() => i *= 2)().take(10); assert(equal(powersOfTwo, iota(1, 11).map!"2^^a"()));
import std.algorithm.comparison : equal; //Returns a runtime delegate auto infiniteIota(T)(T low, T high) { T i = high; return (){if (i == high) i = low; return i++;}; } //adapted as a range. assert(equal(generate(infiniteIota(1, 4)).take(10), [1, 2, 3, 1, 2, 3, 1, 2, 3, 1]));
import std.format : format; import std.random : uniform; auto r = generate!(() => uniform(0, 6)).take(10); format("%(%s %)", r);
Repeats the given forward range ad infinitum. If the original range is infinite (fact that would make Cycle
the identity application), Cycle
detects that and aliases itself to the range type itself. That works for nonforward ranges too. If the original range has random access, Cycle
offers random access and also offers a constructor taking an initial position index
. Cycle
works with static arrays in addition to ranges, mostly for performance reasons.
Range primitives
import std.algorithm.comparison : equal; import std.range : cycle, take; // Here we create an infinitive cyclic sequence from [1, 2] // (i.e. get here [1, 2, 1, 2, 1, 2 and so on]) then // take 5 elements of this sequence (so we have [1, 2, 1, 2, 1]) // and compare them with the expected values for equality. assert(cycle([1, 2]).take(5).equal([ 1, 2, 1, 2, 1 ]));
Range primitives
Iterate several ranges
in lockstep. The element type is a proxy tuple that allows accessing the current element in the n
th range by using e[n]
.
zip
is similar to lockstep
, but lockstep
doesn't bundle its elements and uses the opApply
protocol. lockstep
allows reference access to the elements in foreach
iterations.
StoppingPolicy sp
 controls what zip will do if the ranges are different lengths 
Ranges ranges
 the ranges to zip together 
Zip
offers the lowest range facilities of all components, e.g. it offers random access iff all ranges
offer random access, and also offers mutation and swapping if all ranges
offer it. Due to this, Zip
is extremely powerful because it allows manipulating several ranges
in lockstep. Exception
if all of the ranges are not the same length and sp
is set to StoppingPolicy.requireSameLength
.import std.algorithm.comparison : equal; import std.algorithm.iteration : map; // pairwise sum auto arr = [0, 1, 2]; assert(zip(arr, arr.dropOne).map!"a[0] + a[1]".equal([1, 3]));
import std.conv : to; int[] a = [ 1, 2, 3 ]; string[] b = [ "a", "b", "c" ]; string[] result; foreach (tup; zip(a, b)) { result ~= tup[0].to!string ~ tup[1]; } writeln(result); // ["1a", "2b", "3c"] size_t idx = 0; // unpacking tuple elements with foreach foreach (e1, e2; zip(a, b)) { writeln(e1); // a[idx] writeln(e2); // b[idx] ++idx; }
zip
is powerful  the following code sorts two arrays in parallel: import std.algorithm.sorting : sort; int[] a = [ 1, 2, 3 ]; string[] b = [ "a", "c", "b" ]; zip(a, b).sort!((t1, t2) => t1[0] > t2[0]); writeln(a); // [3, 2, 1] // b is sorted according to a's sorting writeln(b); // ["b", "c", "a"]
Builds an object. Usually this is invoked indirectly by using the zip
function.
Returns true
if the range is at end. The test depends on the stopping policy.
Returns the current iterated element.
Sets the front
of all iterated ranges.
Moves out the front.
Returns the rightmost element.
Moves out the back.
Returns the rightmost element.
Returns the current iterated element.
Returns the rightmost element.
Advances to the next element in all controlled ranges.
Calls popBack
for all controlled ranges.
Returns the length
of this range. Defined only if all ranges define length
.
Returns the length of this range. Defined only if all ranges define length
.
Returns a slice of the range. Defined only if all range define slicing.
Returns the n
th element in the composite range. Defined if all ranges offer random access.
Assigns to the n
th element in the composite range. Defined if all ranges offer random access.
Returns the n
th element in the composite range. Defined if all ranges offer random access.
Destructively reads the n
th element in the composite range. Defined if all ranges offer random access.
Returns the n
th element in the composite range. Defined if all ranges offer random access.
Dictates how iteration in a Zip
should stop. By default stop at the end of the shortest of all ranges.
Stop when the shortest
range is exhausted
Stop when the longest
range is exhausted
Require that all ranges are equal
Iterate multiple ranges
in lockstep
using a foreach
loop. In contrast to zip
it allows reference access to its elements. If only a single range is passed in, the Lockstep
aliases itself away. If the ranges
are of different lengths and s
== StoppingPolicy.shortest
stop after the shortest range is empty. If the ranges
are of different lengths and s
== StoppingPolicy.requireSameLength
, throw an exception. s
may not be StoppingPolicy.longest
, and passing this will throw an exception.
Iterating over Lockstep
in reverse and with an index is only possible when s
== StoppingPolicy.requireSameLength
, in order to preserve indexes. If an attempt is made at iterating in reverse when s
== StoppingPolicy.shortest
, an exception will be thrown.
By default StoppingPolicy
is set to StoppingPolicy.shortest
.
zip
lockstep
is similar to zip
, but zip
bundles its elements and returns a range. lockstep
also supports reference access. Use zip
if you want to pass the result to a range function.auto arr1 = [1,2,3,4,5,100]; auto arr2 = [6,7,8,9,10]; foreach (ref a, b; lockstep(arr1, arr2)) { a += b; } writeln(arr1); // [7, 9, 11, 13, 15, 100] /// Lockstep also supports iterating with an index variable: foreach (index, a, b; lockstep(arr1, arr2)) { writeln(arr1[index]); // a writeln(arr2[index]); // b }
Creates a mathematical sequence given the initial
values and a recurrence
function that computes the next value from the existing values. The sequence comes in the form of an infinite forward range. The type Recurrence
itself is seldom used directly; most often, recurrences are obtained by calling the function recurrence
.
When calling recurrence
, the function that computes the next value is specified as a template argument, and the initial
values in the recurrence
are passed as regular arguments. For example, in a Fibonacci sequence, there are two initial
values (and therefore a state size of 2) because computing the next Fibonacci value needs the past two values.
The signature of this function should be:
auto fun(R)(R state, size_t n)where
n
will be the index of the current value, and state
will be an opaque state vector that can be indexed with arrayindexing notation state[i]
, where valid values of i
range from (n  1)
to (n  State.length)
. "a"
and the zerobased index in the recurrence
has name "n"
. The given string must return the desired value for a[n]
given a[n  1]
, a[n  2]
, a[n  3]
,..., a[n  stateSize]
. The state size is dictated by the number of arguments passed to the call to recurrence
. The Recurrence
struct itself takes care of managing the recurrence
's state and shifting it appropriately. import std.algorithm.comparison : equal; // The Fibonacci numbers, using function in string form: // a[0] = 1, a[1] = 1, and compute a[n+1] = a[n1] + a[n] auto fib = recurrence!("a[n1] + a[n2]")(1, 1); assert(fib.take(10).equal([1, 1, 2, 3, 5, 8, 13, 21, 34, 55])); // The factorials, using function in lambda form: auto fac = recurrence!((a,n) => a[n1] * n)(1); assert(take(fac, 10).equal([ 1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880 ])); // The triangular numbers, using function in explicit form: static size_t genTriangular(R)(R state, size_t n) { return state[n1] + n; } auto tri = recurrence!genTriangular(0); assert(take(tri, 10).equal([0, 1, 3, 6, 10, 15, 21, 28, 36, 45]));
Sequence
is similar to Recurrence
except that iteration is presented in the socalled closed form. This means that the n
th element in the series is computable directly from the initial values and n
itself. This implies that the interface offered by Sequence
is a randomaccess range, as opposed to the regular Recurrence
, which only offers forward iteration.
The state of the sequence
is stored as a Tuple
so it can be heterogeneous.
auto odds = sequence!("a[0] + n * a[1]")(1, 2); writeln(odds.front); // 1 odds.popFront(); writeln(odds.front); // 3 odds.popFront(); writeln(odds.front); // 5
auto tri = sequence!((a,n) => n*(n+1)/2)(); // Note random access writeln(tri[0]); // 0 writeln(tri[3]); // 6 writeln(tri[1]); // 1 writeln(tri[4]); // 10 writeln(tri[2]); // 3
import std.math : pow, round, sqrt; static ulong computeFib(S)(S state, size_t n) { // Binet's formula return cast(ulong)(round((pow(state[0], n+1)  pow(state[1], n+1)) / state[2])); } auto fib = sequence!computeFib( (1.0 + sqrt(5.0)) / 2.0, // Golden Ratio (1.0  sqrt(5.0)) / 2.0, // Conjugate of Golden Ratio sqrt(5.0)); // Note random access with [] operator writeln(fib[1]); // 1 writeln(fib[4]); // 5 writeln(fib[3]); // 3 writeln(fib[2]); // 2 writeln(fib[9]); // 55
Creates a range of values that span the given starting and stopping values.
B begin
 The starting value. 
E end
 The value that serves as the stopping criterion. This value is not included in the range. 
S step
 The value to add to the current value at each iteration. 
begin
, begin + step
, begin + 2 * step
, ...
, up to and excluding end
. The twoargument overloads have step = 1
. If begin < end && step < 0
or begin > end && step > 0
or begin == end
, then an empty range is returned. If step == 0
then begin == end
is an error. For builtin types, the range returned is a random access range. For userdefined types that support ++
, the range is an input range. An integral iota
also supports in
operator from the right. It takes the stepping into account, the integral won't be considered contained if it falls between two consecutive values of the range. contains
does the same as in, but from lefthand side. void main() { import std.stdio; // The following groups all produce the same output of: // 0 1 2 3 4 foreach (i; 0 .. 5) writef("%s ", i); writeln(); import std.range : iota; foreach (i; iota(0, 5)) writef("%s ", i); writeln(); writefln("%(%s %%)", iota(0, 5)); import std.algorithm.iteration : map; import std.algorithm.mutation : copy; import std.format; iota(0, 5).map!(i => format("%s ", i)).copy(stdout.lockingTextWriter()); writeln(); }
import std.algorithm.comparison : equal; import std.math : approxEqual; auto r = iota(0, 10, 1); assert(equal(r, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9])); assert(equal(r, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9])); assert(3 in r); assert(r.contains(3)); //Same as above assert(!(10 in r)); assert(!(8 in r)); r = iota(0, 11, 3); assert(equal(r, [0, 3, 6, 9])); writeln(r[2]); // 6 assert(!(2 in r)); auto rf = iota(0.0, 0.5, 0.1); assert(approxEqual(rf, [0.0, 0.1, 0.2, 0.3, 0.4]));
Options for the FrontTransversal
and Transversal
ranges (below).
When transversed, the elements of a range of ranges are assumed to have different lengths (e.g. a jagged array).
The transversal enforces that the elements of a range of ranges have all the same length (e.g. an array of arrays, all having the same length). Checking is done once upon construction of the transversal range.
The transversal assumes, without verifying, that the elements of a range of ranges have all the same length. This option is useful if checking was already done from the outside of the range.
Given a range of ranges, iterate transversally through the first elements of each of the enclosed ranges.
import std.algorithm.comparison : equal; int[][] x = new int[][2]; x[0] = [1, 2]; x[1] = [3, 4]; auto ror = frontTransversal(x); assert(equal(ror, [ 1, 3 ][]));
Construction from an input
.
Forward range primitives.
Duplicates this frontTransversal
. Note that only the encapsulating range of range will be duplicated. Underlying ranges will not be duplicated.
Bidirectional primitives. They are offered if isBidirectionalRange!RangeOfRanges
.
Randomaccess primitive. It is offered if isRandomAccessRange!RangeOfRanges && (opt == TransverseOptions.assumeNotJagged  opt == TransverseOptions.enforceNotJagged)
.
Slicing if offered if RangeOfRanges
supports slicing and all the conditions for supporting indexing are met.
Given a range of ranges, iterate transversally through the n
th element of each of the enclosed ranges.
opt  Controls the assumptions the function makes about the lengths of the ranges 
RangeOfRanges rr
 An input range of random access ranges 
rr
provides them.import std.algorithm.comparison : equal; int[][] x = new int[][2]; x[0] = [1, 2]; x[1] = [3, 4]; auto ror = transversal(x, 1); assert(equal(ror, [ 2, 4 ][]));
Construction from an input
and an index.
Forward range primitives.
Bidirectional primitives. They are offered if isBidirectionalRange!RangeOfRanges
.
Randomaccess primitive. It is offered if isRandomAccessRange!RangeOfRanges && (opt == TransverseOptions.assumeNotJagged  opt == TransverseOptions.enforceNotJagged)
.
Slicing if offered if RangeOfRanges
supports slicing and all the conditions for supporting indexing are met.
Given a range of ranges, returns a range of ranges where the i'th subrange contains the i'th elements of the original subranges.
import std.algorithm.comparison : equal; int[][] ror = [ [1, 2, 3], [4, 5, 6] ]; auto xp = transposed(ror); assert(equal!"a.equal(b)"(xp, [ [1, 4], [2, 5], [3, 6] ]));
int[][] x = new int[][2]; x[0] = [1, 2]; x[1] = [3, 4]; auto tr = transposed(x); int[][] witness = [ [ 1, 3 ], [ 2, 4 ] ]; uint i; foreach (e; tr) { writeln(array(e)); // witness[i++] }
This struct takes two ranges, source
and indices
, and creates a view of source
as if its elements were reordered according to indices
. indices
may include only a subset of the elements of source
and may also repeat elements.
Source
must be a random access range. The returned range will be bidirectional or randomaccess if Indices
is bidirectional or randomaccess, respectively.
import std.algorithm.comparison : equal; auto source = [1, 2, 3, 4, 5]; auto indices = [4, 3, 1, 2, 0, 4]; auto ind = indexed(source, indices); assert(equal(ind, [5, 4, 2, 3, 1, 5])); assert(equal(retro(ind), [5, 1, 3, 2, 4, 5]));
Range primitives
Returns the source
range.
Returns the indices
range.
Returns the physical index into the source range corresponding to a given logical index. This is useful, for example, when indexing an Indexed
without adding another layer of indirection.
auto ind = indexed([1, 2, 3, 4, 5], [1, 3, 4]); writeln(ind.physicalIndex(0)); // 1
This range iterates over fixedsized chunks
of size chunkSize
of a source
range. Source
must be an input range. chunkSize
must be greater than zero.
If !isInfinite!Source
and source.walkLength
is not evenly divisible by chunkSize
, the back element of this range will contain fewer than chunkSize
elements.
If Source
is a forward range, the resulting range will be forward ranges as well. Otherwise, the resulting chunks
will be input ranges consuming the same input: iterating over front
will shrink the chunk such that subsequent invocations of front
will no longer return the full chunk, and calling popFront
on the outer range will invalidate any lingering references to previous values of front
.
Source source
 Range from which the chunks will be selected 
size_t chunkSize
 Chunk size 
slide
chunks
.import std.algorithm.comparison : equal; auto source = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; auto chunks = chunks(source, 4); writeln(chunks[0]); // [1, 2, 3, 4] writeln(chunks[1]); // [5, 6, 7, 8] writeln(chunks[2]); // [9, 10] writeln(chunks.back); // chunks[2] writeln(chunks.front); // chunks[0] writeln(chunks.length); // 3 assert(equal(retro(array(chunks)), array(retro(chunks))));
import std.algorithm.comparison : equal; int i; // The generator doesn't save state, so it cannot be a forward range. auto inputRange = generate!(() => ++i).take(10); // We can still process it in chunks, but it will be singlepass only. auto chunked = inputRange.chunks(2); assert(chunked.front.equal([1, 2])); assert(chunked.front.empty); // Iterating the chunk has consumed it chunked.popFront; assert(chunked.front.equal([3, 4]));
Standard constructor
Input range primitives. Always present.
Forward range primitives. Only present if Source
is a forward range.
Length. Only if hasLength!Source
is true
Indexing and slicing operations. Provided only if hasSlicing!Source
is true
.
Bidirectional range primitives. Provided only if both hasSlicing!Source
and hasLength!Source
are true
.
This range splits a source
range into chunkCount
chunks of approximately equal length. Source
must be a forward range with known length.
Unlike chunks
, evenChunks
takes a chunk count (not size). The returned range will contain zero or more source.length / chunkCount + 1
elements followed by source.length / chunkCount
elements. If source.length < chunkCount
, some chunks will be empty.
chunkCount
must not be zero, unless source
is also empty.
import std.algorithm.comparison : equal; auto source = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; auto chunks = evenChunks(source, 3); writeln(chunks[0]); // [1, 2, 3, 4] writeln(chunks[1]); // [5, 6, 7] writeln(chunks[2]); // [8, 9, 10]
Standard constructor
Forward range primitives. Always present.
Length
Indexing, slicing and bidirectional operations and range primitives. Provided only if hasSlicing!Source
is true
.
Assemble values
into a range that carries all its elements insitu.
Useful when a single value or multiple disconnected values
must be passed to an algorithm expecting a range, without having to perform dynamic memory allocation.
As copying the range means copying all elements, it can be safely returned from functions. For the same reason, copying the returned range may be expensive for a large number of arguments.
Values values
 the values to assemble together 
RandomAccessRange
of the assembled values
. chain
to chain rangesimport std.algorithm.comparison : equal; import std.algorithm.iteration : filter, joiner, map; import std.algorithm.searching : findSplitBefore; import std.uni : isUpper; assert(equal(only('♡'), "♡")); writeln([1, 2, 3, 4].findSplitBefore(only(3))[0]); // [1, 2] assert(only("one", "two", "three").joiner(" ").equal("one two three")); string title = "The D Programming Language"; assert(title .filter!isUpper // take the upper case letters .map!only // make each letter its own range .joiner(".") // join the ranges together lazily .equal("T.D.P.L"));
Iterate over range
with an attached index variable.
Each element is a std.typecons.Tuple
containing the index and the element, in that order, where the index member is named index
and the element member is named value
.
The index starts at start
and is incremented by one on every iteration.
range
has length, then it is an error to pass a value for start
so that start + range.length
is bigger than Enumerator.max
, thus it is ensured that overflow cannot happen. range
does not have length, and popFront
is called when front.index == Enumerator.max
, the index will overflow and continue from Enumerator.min
. Range range
 the input range to attach indexes to 
Enumerator start
 the number to start the index counter from 
range
. All other range
primitives are given in the resulting range
if range
has them. The exceptions are the bidirectional primitives, which are propagated only if range
has length. foreach
with an index loop variable: import std.stdio : stdin, stdout; import std.range : enumerate; foreach (lineNum, line; stdin.byLine().enumerate(1)) stdout.writefln("line #%s: %s", lineNum, line);
start
enumeration from a negative position: import std.array : assocArray; import std.range : enumerate; bool[int] aa = true.repeat(3).enumerate(1).assocArray(); assert(aa[1]); assert(aa[0]); assert(aa[1]);
Returns true
if fn
accepts variables of type T1 and T2 in any order. The following code should compile:
T1 foo(); T2 bar(); fn(foo(), bar()); fn(bar(), foo());
Policy used with the searching primitives lowerBound
, upperBound
, and equalRange
of SortedRange
below.
Searches in a linear
fashion.
Searches with a step that is grows linearly (1, 2, 3,...) leading to a quadratic search schedule (indexes tried are 0, 1, 3, 6, 10, 15, 21, 28,...) Once the search overshoots its target, the remaining interval is searched using binary search. The search is completed in Ο(sqrt(n)
) time. Use it when you are reasonably confident that the value is around the beginning of the range.
Performs a galloping search algorithm, i.e. searches with a step that doubles every time, (1, 2, 4, 8, ...) leading to an exponential search schedule (indexes tried are 0, 1, 3, 7, 15, 31, 63,...) Once the search overshoots its target, the remaining interval is searched using binary search. A value is found in Ο(log(n)
) time.
Searches using a classic interval halving policy. The search starts in the middle of the range, and each search step cuts the range in half. This policy finds a value in Ο(log(n)
) time but is less cache friendly than gallop
for large ranges. The binarySearch
policy is used as the last step of trot
, gallop
, trotBackwards
, and gallopBackwards
strategies.
Similar to trot
but starts backwards. Use it when confident that the value is around the end of the range.
Similar to gallop
but starts backwards. Use it when confident that the value is around the end of the range.
Represents a sorted range. In addition to the regular range primitives, supports additional operations that take advantage of the ordering, such as merge and binary search. To obtain a SortedRange
from an unsorted range r
, use std.algorithm.sorting.sort
which sorts r
in place and returns the corresponding SortedRange
. To construct a SortedRange
from a range r
that is known to be already sorted, use assumeSorted
described below.
import std.algorithm.sorting : sort; auto a = [ 1, 2, 3, 42, 52, 64 ]; auto r = assumeSorted(a); assert(r.contains(3)); assert(!r.contains(32)); auto r1 = sort!"a > b"(a); assert(r1.contains(3)); assert(!r1.contains(32)); writeln(r1.release()); // [64, 52, 42, 3, 2, 1]
SortedRange
could accept ranges weaker than randomaccess, but it is unable to provide interesting functionality for them. Therefore, SortedRange
is currently restricted to randomaccess ranges. No copy of the original range is ever made. If the underlying range is changed concurrently with its corresponding SortedRange
in ways that break its sortedness, SortedRange
will work erratically. import std.algorithm.mutation : swap; auto a = [ 1, 2, 3, 42, 52, 64 ]; auto r = assumeSorted(a); assert(r.contains(42)); swap(a[3], a[5]); // illegal to break sortedness of original range assert(!r.contains(42)); // passes although it shouldn't
Range primitives.
Releases the controlled range and returns it.
This function uses a search with policy sp
to find the largest left subrange on which pred(x, value)
is true
for all x
(e.g., if pred
is "less than", returns the portion of the range with elements strictly smaller than value
). The search schedule and its complexity are documented in SearchPolicy
. See also STL's lower_bound.
import std.algorithm.comparison : equal; auto a = assumeSorted([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ]); auto p = a.lowerBound(4); assert(equal(p, [ 0, 1, 2, 3 ]));
This function searches with policy sp
to find the largest right subrange on which pred(value, x)
is true
for all x
(e.g., if pred
is "less than", returns the portion of the range with elements strictly greater than value
). The search schedule and its complexity are documented in SearchPolicy
.
For ranges that do not offer random access, SearchPolicy.linear
is the only policy allowed (and it must be specified explicitly lest it exposes user code to unexpected inefficiencies). For randomaccess searches, all policies are allowed, and SearchPolicy.binarySearch
is the default.
import std.algorithm.comparison : equal; auto a = assumeSorted([ 1, 2, 3, 3, 3, 4, 4, 5, 6 ]); auto p = a.upperBound(3); assert(equal(p, [4, 4, 5, 6]));
Returns the subrange containing all elements e
for which both pred(e, value)
and pred(value, e)
evaluate to false
(e.g., if pred
is "less than", returns the portion of the range with elements equal to value
). Uses a classic binary search with interval halving until it finds a value
that satisfies the condition, then uses SearchPolicy.gallopBackwards
to find the left boundary and SearchPolicy.gallop
to find the right boundary. These policies are justified by the fact that the two boundaries are likely to be near the first found value
(i.e., equal ranges are relatively small). Completes the entire search in Ο(log(n)
) time. See also STL's equal_range.
import std.algorithm.comparison : equal; auto a = [ 1, 2, 3, 3, 3, 4, 4, 5, 6 ]; auto r = a.assumeSorted.equalRange(3); assert(equal(r, [ 3, 3, 3 ]));
Returns a tuple r
such that r[0]
is the same as the result of lowerBound(value)
, r[1]
is the same as the result of equalRange(value)
, and r[2]
is the same as the result of upperBound(value)
. The call is faster than computing all three separately. Uses a search schedule similar to equalRange
. Completes the entire search in Ο(log(n)
) time.
import std.algorithm.comparison : equal; auto a = [ 1, 2, 3, 3, 3, 4, 4, 5, 6 ]; auto r = assumeSorted(a).trisect(3); assert(equal(r[0], [ 1, 2 ])); assert(equal(r[1], [ 3, 3, 3 ])); assert(equal(r[2], [ 4, 4, 5, 6 ]));
Returns true
if and only if value
can be found in range
, which is assumed to be sorted. Performs Ο(log(r.length)
) evaluations of pred
. See also STL's binary_search.
Returns a range of subranges of elements that are equivalent according to the sorting relation.
Assumes r
is sorted by predicate pred
and returns the corresponding SortedRange!(pred, R)
having r
as support. To keep the checking costs low, the cost is Ο(1
) in release mode (no checks for sortedness are performed). In debug mode, a few random elements of r
are checked for sortedness. The size of the sample is proportional Ο(log(r.length)
). That way, checking has no effect on the complexity of subsequent operations specific to sorted ranges (such as binary search). The probability of an arbitrary unsorted range failing the test is very high (however, an almostsorted range is likely to pass it). To check for sortedness at cost Ο(n
), use std.algorithm.sorting.isSorted
.
Wrapper which effectively makes it possible to pass a range
by reference. Both the original range
and the RefRange
will always have the exact same elements. Any operation done on one will affect the other. So, for instance, if it's passed to a function which would implicitly copy the original range
if it were passed to it, the original range
is not copied but is consumed as if it were a reference type.
save
works as normal and operates on a new range, so if save
is ever called on the RefRange
, then no operations on the saved range will affect the original. R* range
 the range to construct the RefRange from 
RefRange
. If the given range is a class type (and thus is already a reference type), then the original range
is returned rather than a RefRange
.import std.algorithm.searching : find; ubyte[] buffer = [1, 9, 45, 12, 22]; auto found1 = find(buffer, 45); writeln(found1); // [45, 12, 22] writeln(buffer); // [1, 9, 45, 12, 22] auto wrapped1 = refRange(&buffer); auto found2 = find(wrapped1, 45); writeln(*found2.ptr); // [45, 12, 22] writeln(buffer); // [45, 12, 22] auto found3 = find(wrapped1.save, 22); writeln(*found3.ptr); // [22] writeln(buffer); // [45, 12, 22] string str = "hello world"; auto wrappedStr = refRange(&str); writeln(str.front); // 'h' str.popFrontN(5); writeln(str); // " world" writeln(wrappedStr.front); // ' ' writeln(*wrappedStr.ptr); // " world"
ubyte[] buffer1 = [1, 2, 3, 4, 5]; ubyte[] buffer2 = [6, 7, 8, 9, 10]; auto wrapped1 = refRange(&buffer1); auto wrapped2 = refRange(&buffer2); assert(wrapped1.ptr is &buffer1); assert(wrapped2.ptr is &buffer2); assert(wrapped1.ptr !is wrapped2.ptr); assert(buffer1 != buffer2); wrapped1 = wrapped2; //Everything points to the same stuff as before. assert(wrapped1.ptr is &buffer1); assert(wrapped2.ptr is &buffer2); assert(wrapped1.ptr !is wrapped2.ptr); //But buffer1 has changed due to the assignment. writeln(buffer1); // [6, 7, 8, 9, 10] writeln(buffer2); // [6, 7, 8, 9, 10] buffer2 = [11, 12, 13, 14, 15]; //Everything points to the same stuff as before. assert(wrapped1.ptr is &buffer1); assert(wrapped2.ptr is &buffer2); assert(wrapped1.ptr !is wrapped2.ptr); //But buffer2 has changed due to the assignment. writeln(buffer1); // [6, 7, 8, 9, 10] writeln(buffer2); // [11, 12, 13, 14, 15] wrapped2 = null; //The pointer changed for wrapped2 but not wrapped1. assert(wrapped1.ptr is &buffer1); assert(wrapped2.ptr is null); assert(wrapped1.ptr !is wrapped2.ptr); //buffer2 is not affected by the assignment. writeln(buffer1); // [6, 7, 8, 9, 10] writeln(buffer2); // [11, 12, 13, 14, 15]
import std.algorithm.iteration : map, joiner, group; import std.algorithm.searching : until; // fix for std.algorithm auto r = map!(x => 0)([1]); chain(r, r); zip(r, r); roundRobin(r, r); struct NRAR { typeof(r) input; @property empty() { return input.empty; } @property front() { return input.front; } void popFront() { input.popFront(); } @property save() { return NRAR(input.save); } } auto n1 = NRAR(r); cycle(n1); // non random access range version assumeSorted(r); // fix for std.range joiner([r], [9]); struct NRAR2 { NRAR input; @property empty() { return true; } @property front() { return input; } void popFront() { } @property save() { return NRAR2(input.save); } } auto n2 = NRAR2(n1); joiner(n2); group(r); until(r, 7); static void foo(R)(R r) { until!(x => x > 7)(r); } foo(r);
This does not assign the pointer of rhs
to this RefRange
. Rather it assigns the range pointed to by rhs
to the range pointed to by this RefRange
. This is because any operation on a RefRange
is the same is if it occurred to the original range. The one exception is when a RefRange
is assigned null
either directly or because rhs
is null
. In that case, RefRange
no longer refers to the original range but is null
.
A pointer to the wrapped range.
Only defined if isForwardRange!R
is true
.
Only defined if isBidirectionalRange!R
is true
.
Only defined if isRandomAccesRange!R
is true
.
Only defined if hasMobileElements!R
and isForwardRange!R
are true
.
Only defined if hasMobileElements!R
and isBidirectionalRange!R
are true
.
Only defined if hasMobileElements!R
and isRandomAccessRange!R
are true
.
Only defined if hasLength!R
is true
.
Only defined if hasSlicing!R
is true
.
Bitwise adapter over an integral type range
. Consumes the range
elements bit by bit, from the least significant bit to the most significant bit.
R  an integral input range to iterate over 
R range

range to consume bit by by 
Bitwise
input range
with propagated forward, bidirectional and random access capabilitiesimport std.algorithm.comparison : equal; import std.format : format; // 00000011 00001001 ubyte[] arr = [3, 9]; auto r = arr.bitwise; // iterate through it as with any other range writeln(format("%(%d%)", r)); // "1100000010010000" assert(format("%(%d%)", r.retro).equal("1100000010010000".retro)); auto r2 = r[5 .. $]; // set a bit r[2] = 1; writeln(arr[0]); // 7 writeln(r[5]); // r2[0]
bitwise
to implement an uniform bool generator import std.algorithm.comparison : equal; import std.random : rndGen; auto rb = rndGen.bitwise; static assert(isInfinite!(typeof(rb))); auto rb2 = rndGen.bitwise; // Don't forget that structs are passed by value assert(rb.take(10).equal(rb2.take(10)));
An OutputRange that discards the data it receives.
import std.algorithm.iteration : map; import std.algorithm.mutation : copy; [4, 5, 6].map!(x => x * 2).copy(NullSink()); // data is discarded
Implements a "tee
" style pipe, wrapping an input range so that elements of the range can be passed to a provided function or OutputRange
as they are iterated over. This is useful for printing out intermediate values in a long chain of range code, performing some operation with sideeffects on each call to front
or popFront
, or diverting the elements of a range into an auxiliary OutputRange
.
It is important to note that as the resultant range is evaluated lazily, in the case of the version of tee
that takes a function, the function will not actually be executed until the range is "walked" using functions that evaluate ranges, such as std.array.array
or std.algorithm.iteration.fold
.
pipeOnPop  If Yes.pipeOnPop , simply iterating the range without ever calling front is enough to have tee mirror elements to outputRange (or, respectively, fun ). If No.pipeOnPop , only elements for which front does get called will be also sent to outputRange /fun . 
R1 inputRange
 The input range being passed through. 
R2 outputRange
 This range will receive elements of inputRange progressively as iteration proceeds. 
fun  This function will be called with elements of inputRange progressively as iteration proceeds. 
inputRange
. Regardless of whether inputRange
is a more powerful range (forward, bidirectional etc), the result is always an input range. Reading this causes inputRange
to be iterated and returns its elements in turn. In addition, the same elements will be passed to outputRange
or fun
as well. std.algorithm.iteration.each
import std.algorithm.comparison : equal; import std.algorithm.iteration : filter, map; // Sum values while copying int[] values = [1, 4, 9, 16, 25]; int sum = 0; auto newValues = values.tee!(a => sum += a).array; assert(equal(newValues, values)); writeln(sum); // 1 + 4 + 9 + 16 + 25 // Count values that pass the first filter int count = 0; auto newValues4 = values.filter!(a => a < 10) .tee!(a => count++) .map!(a => a + 1) .filter!(a => a < 10); //Fine, equal also evaluates any lazy ranges passed to it. //count is not 3 until equal evaluates newValues4 assert(equal(newValues4, [2, 5])); writeln(count); // 3
Extends the length of the input range r
by padding out the start of the range with the element e
. The element e
must be of a common type with the element type of the range r
as defined by std.traits.CommonType
. If n
is less than the length of of r
, then r
is returned unmodified.
If r
is a string with Unicode characters in it, padLeft
follows D's rules about length for strings, which is not the number of characters, or graphemes, but instead the number of encoding units. If you want to treat each grapheme as only one encoding unit long, then call std.uni.byGrapheme
before calling this function.
If r
has a length, then this is Ο(1
). Otherwise, it's Ο(r.length
).
R r
 an input range with a length, or a forward range 
E e
 element to pad the range with 
size_t n
 the length to pad to 
std.string.leftJustifier
import std.algorithm.comparison : equal; assert([1, 2, 3, 4].padLeft(0, 6).equal([0, 0, 1, 2, 3, 4])); assert([1, 2, 3, 4].padLeft(0, 3).equal([1, 2, 3, 4])); assert("abc".padLeft('_', 6).equal("___abc"));
Extend the length of the input range r
by padding out the end of the range with the element e
. The element e
must be of a common type with the element type of the range r
as defined by std.traits.CommonType
. If n
is less than the length of of r
, then the contents of r
are returned.
The range primitives that the resulting range provides depends whether or not r
provides them. Except the functions back
and popBack
, which also require the range to have a length as well as back
and popBack
R r
 an input range with a length 
E e
 element to pad the range with 
size_t n
 the length to pad to 
std.string.rightJustifier
import std.algorithm.comparison : equal; assert([1, 2, 3, 4].padRight(0, 6).equal([1, 2, 3, 4, 0, 0])); assert([1, 2, 3, 4].padRight(0, 4).equal([1, 2, 3, 4])); assert("abc".padRight('_', 6).equal("abc___"));
© 1999–2017 The D Language Foundation
Licensed under the Boost License 1.0.
https://dlang.org/phobos/std_range.html