Report a bug
If you spot a problem with this page, click here to create a Bugzilla issue.
Improve this page
Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using a local clone.

std.array

Functions and types that manipulate built-in arrays and associative arrays.
This module provides all kinds of functions to create, manipulate or convert arrays:
Function Name Description
array Returns a copy of the input in a newly allocated dynamic array.
appender Returns a new Appender or RefAppender initialized with a given array.
assocArray Returns a newly allocated associative array from a range of key/value tuples.
byPair Construct a range iterating over an associative array by key/value tuples.
insertInPlace Inserts into an existing array at a given position.
join Concatenates a range of ranges into one array.
minimallyInitializedArray Returns a new array of type T.
replace Returns a new array with all occurrences of a certain subrange replaced.
replaceFirst Returns a new array with the first occurrence of a certain subrange replaced.
replaceInPlace Replaces all occurrences of a certain subrange and puts the result into a given array.
replaceInto Replaces all occurrences of a certain subrange and puts the result into an output range.
replaceLast Returns a new array with the last occurrence of a certain subrange replaced.
replaceSlice Returns a new array with a given slice replaced.
replicate Creates a new array out of several copies of an input array or range.
sameHead Checks if the initial segments of two arrays refer to the same place in memory.
sameTail Checks if the final segments of two arrays refer to the same place in memory.
split Eagerly split a range or string into an array.
uninitializedArray Returns a new array of type T without initializing its elements.
Authors:
Andrei Alexandrescu and Jonathan M Davis
ForeachType!Range[] array(Range)(Range r)
if (isIterable!Range && !isNarrowString!Range && !isInfinite!Range);
Allocates an array and initializes it with copies of the elements of range r.
Narrow strings are handled as a special case in an overload.
Parameters:
Range r range (or aggregate with opApply function) whose elements are copied into the allocated array
Returns:
allocated and initialized array
Examples:
auto a = array([1, 2, 3, 4, 5][]);
writeln(a); // [1, 2, 3, 4, 5]
@trusted ElementType!String[] array(String)(scope String str)
if (isNarrowString!String);
Convert a narrow string to an array type that fully supports random access. This is handled as a special case and always returns an array of dchar
Parameters:
String str isNarrowString to be converted to an array of dchar
Returns:
a dchar[], const(dchar)[], or immutable(dchar)[] depending on the constness of the input.
Examples:
import std.range.primitives : isRandomAccessRange;

writeln("Hello D".array); // "Hello D"d
static assert(isRandomAccessRange!string == false);

writeln("Hello D"w.array); // "Hello D"d
static assert(isRandomAccessRange!dstring == true);
auto assocArray(Range)(Range r)
if (isInputRange!Range);
Returns a newly allocated associative array from a range of key/value tuples.
Parameters:
Range r An input range of tuples of keys and values.
Returns:
A newly allocated associative array out of elements of the input range, which must be a range of tuples (Key, Value). Returns a null associative array reference when given an empty range.

Duplicates Associative arrays have unique keys. If r contains duplicate keys, then the result will contain the value of the last pair for that key in r.

Examples:
import std.range;
import std.typecons;
auto a = assocArray(zip([0, 1, 2], ["a", "b", "c"])); // aka zipMap
assert(is(typeof(a) == string[int]));
writeln(a); // [0:"a", 1:"b", 2:"c"]

auto b = assocArray([ tuple("foo", "bar"), tuple("baz", "quux") ]);
assert(is(typeof(b) == string[string]));
writeln(b); // ["foo":"bar", "baz":"quux"]
auto byPair(AA : Value[Key], Value, Key)(AA aa);
Construct a range iterating over an associative array by key/value tuples.
Parameters:
AA aa The associative array to iterate over.
Returns:
A forward range of Tuple's of key and value pairs from the given associative array.
Examples:
import std.algorithm.sorting : sort;
import std.typecons : tuple, Tuple;

auto aa = ["a": 1, "b": 2, "c": 3];
Tuple!(string, int)[] pairs;

// Iteration over key/value pairs.
foreach (pair; aa.byPair)
{
    pairs ~= pair;
}

// Iteration order is implementation-dependent, so we should sort it to get
// a fixed order.
sort(pairs);
assert(pairs == [
    tuple("a", 1),
    tuple("b", 2),
    tuple("c", 3)
]);
nothrow @system auto uninitializedArray(T, I...)(I sizes)
if (isDynamicArray!T && allSatisfy!(isIntegral, I) && hasIndirections!(ElementEncodingType!T));

nothrow @trusted auto uninitializedArray(T, I...)(I sizes)
if (isDynamicArray!T && allSatisfy!(isIntegral, I) && !hasIndirections!(ElementEncodingType!T));
Returns a new array of type T allocated on the garbage collected heap without initializing its elements. This can be a useful optimization if every element will be immediately initialized. T may be a multidimensional array. In this case sizes may be specified for any number of dimensions from 0 to the number in T.
uninitializedArray is nothrow and weakly pure.
uninitializedArray is @system if the uninitialized element type has pointers.
Examples:
double[] arr = uninitializedArray!(double[])(100);
writeln(arr.length); // 100

double[][] matrix = uninitializedArray!(double[][])(42, 31);
writeln(matrix.length); // 42
writeln(matrix[0].length); // 31

char*[] ptrs = uninitializedArray!(char*[])(100);
writeln(ptrs.length); // 100
nothrow @trusted auto minimallyInitializedArray(T, I...)(I sizes)
if (isDynamicArray!T && allSatisfy!(isIntegral, I));
Returns a new array of type T allocated on the garbage collected heap.
Partial initialization is done for types with indirections, for preservation of memory safety. Note that elements will only be initialized to 0, but not necessarily the element type's .init.
minimallyInitializedArray is nothrow and weakly pure.
Examples:
import std.algorithm.comparison : equal;
import std.range : repeat;

auto arr = minimallyInitializedArray!(int[])(42);
writeln(arr.length); // 42
// Elements aren't necessarily initialized to 0
assert(!arr.equal(0.repeat(42)));
void insertInPlace(T, U...)(ref T[] array, size_t pos, U stuff)
if (!isSomeString!(T[]) && allSatisfy!(isInputRangeOrConvertible!T, U) && U.length > 0);

void insertInPlace(T, U...)(ref T[] array, size_t pos, U stuff)
if (isSomeString!(T[]) && allSatisfy!(isCharOrStringOrDcharRange, U));
Inserts stuff (which must be an input range or any number of implicitly convertible items) in array at position pos.
Parameters:
T[] array The array that stuff will be inserted into.
size_t pos The position in array to insert the stuff.
U stuff An input range, or any number of implicitly convertible items to insert into array.
Examples:
int[] a = [ 1, 2, 3, 4 ];
a.insertInPlace(2, [ 1, 2 ]);
writeln(a); // [1, 2, 1, 2, 3, 4]
a.insertInPlace(3, 10u, 11);
writeln(a); // [1, 2, 1, 10, 11, 2, 3, 4]
pure nothrow @safe bool sameHead(T)(in T[] lhs, in T[] rhs);
Returns whether the fronts of lhs and rhs both refer to the same place in memory, making one of the arrays a slice of the other which starts at index 0.
Examples:
auto a = [1, 2, 3, 4, 5];
auto b = a[0 .. 2];

assert(a.sameHead(b));
pure nothrow @trusted bool sameTail(T)(in T[] lhs, in T[] rhs);
Returns whether the backs of lhs and rhs both refer to the same place in memory, making one of the arrays a slice of the other which end at index $.
Examples:
auto a = [1, 2, 3, 4, 5];
auto b = a[3..$];

assert(a.sameTail(b));
ElementEncodingType!S[] replicate(S)(S s, size_t n)
if (isDynamicArray!S);

ElementType!S[] replicate(S)(S s, size_t n)
if (isInputRange!S && !isDynamicArray!S);
Parameters:
S s an input range or a dynamic array
size_t n number of times to repeat s
Returns:
An array that consists of s repeated n times. This function allocates, fills, and returns a new array.
See Also:
For a lazy version, refer to std.range.repeat.
Examples:
auto a = "abc";
auto s = replicate(a, 3);

writeln(s); // "abcabcabc"

auto b = [1, 2, 3];
auto c = replicate(b, 3);

writeln(c); // [1, 2, 3, 1, 2, 3, 1, 2, 3]

auto d = replicate(b, 0);

writeln(d); // []
pure @safe S[] split(S)(S s)
if (isSomeString!S);
Eagerly split the string s into an array of words, using whitespace as delimiter. Runs of whitespace are merged together (no empty words are produced).
@safe, pure and CTFE-able.
Parameters:
S s the string to split
Returns:
An array of each word in s
See Also:
std.algorithm.iteration.splitter for a version that splits using any separator.
std.regex.splitter for a version that splits using a regular expression defined separator.
Examples:
string str = "Hello World!";
writeln(str.split); // ["Hello", "World!"]

string str2 = "Hello\t\tWorld\t!";
writeln(str2.split); // ["Hello", "World", "!"]
Examples:
split allocates memory, so the same effect can be achieved lazily using std.algorithm.iteration.splitter.
import std.ascii : isWhite;
import std.algorithm.comparison : equal;

string str = "Hello World!";
assert(str.splitter!(isWhite).equal(["Hello", "World!"]));
Examples:
writeln(split("hello world")); // ["hello", "world"]
writeln(split("192.168.0.1", ".")); // ["192", "168", "0", "1"]

auto a = split([1, 2, 3, 4, 5, 1, 2, 3, 4, 5], [2, 3]);
writeln(a); // [[1], [4, 5, 1], [4, 5]]
auto split(Range, Separator)(Range range, Separator sep)
if (isForwardRange!Range && is(typeof(ElementType!Range.init == Separator.init)));

auto split(Range, Separator)(Range range, Separator sep)
if (isForwardRange!Range && isForwardRange!Separator && is(typeof(ElementType!Range.init == ElementType!Separator.init)));

auto split(alias isTerminator, Range)(Range range)
if (isForwardRange!Range && is(typeof(unaryFun!isTerminator(range.front))));
Eagerly splits range into an array, using sep as the delimiter.
The range must be a forward range. The separator can be a value of the same type as the elements in range or it can be another forward range.

Example If range is a string, sep can be a char or another string. The return type will be an array of strings. If range is an int array, sep can be an int or another int array. The return type will be an array of int arrays.

Parameters:
Range range a forward range.
Separator sep a value of the same type as the elements of range or another forward range.
Returns:
An array containing the divided parts of range.
See Also:
std.algorithm.iteration.splitter for the lazy version of this function.
Examples:
import std.uni : isWhite;
writeln("Learning,D,is,fun".split(",")); // ["Learning", "D", "is", "fun"]
writeln("Learning D is fun".split!isWhite); // ["Learning", "D", "is", "fun"]
writeln("Learning D is fun".split(" D ")); // ["Learning", "is fun"]
ElementEncodingType!(ElementType!RoR)[] join(RoR, R)(RoR ror, scope R sep)
if (isInputRange!RoR && isInputRange!(Unqual!(ElementType!RoR)) && isInputRange!R && is(Unqual!(ElementType!(ElementType!RoR)) == Unqual!(ElementType!R)));

ElementEncodingType!(ElementType!RoR)[] join(RoR, E)(RoR ror, scope E sep)
if (isInputRange!RoR && isInputRange!(Unqual!(ElementType!RoR)) && is(E : ElementType!(ElementType!RoR)));

ElementEncodingType!(ElementType!RoR)[] join(RoR)(RoR ror)
if (isInputRange!RoR && isInputRange!(Unqual!(ElementType!RoR)));
Eagerly concatenates all of the ranges in ror together (with the GC) into one array using sep as the separator if present.
Parameters:
RoR ror An input range of input ranges
R sep An input range, or a single element, to join the ranges on
Returns:
An array of elements
See Also:
For a lazy version, see std.algorithm.iteration.joiner
Examples:
writeln(join(["hello", "silly", "world"], " ")); // "hello silly world"
writeln(join(["hello", "silly", "world"])); // "hellosillyworld"

writeln(join([[1, 2, 3], [4, 5]], [72, 73])); // [1, 2, 3, 72, 73, 4, 5]
writeln(join([[1, 2, 3], [4, 5]])); // [1, 2, 3, 4, 5]

const string[] arr = ["apple", "banana"];
writeln(arr.join(",")); // "apple,banana"
writeln(arr.join()); // "applebanana"
E[] replace(E, R1, R2)(E[] subject, R1 from, R2 to)
if (isDynamicArray!(E[]) && isForwardRange!R1 && isForwardRange!R2 && (hasLength!R2 || isSomeString!R2));

void replaceInto(E, Sink, R1, R2)(Sink sink, E[] subject, R1 from, R2 to)
if (isOutputRange!(Sink, E) && isDynamicArray!(E[]) && isForwardRange!R1 && isForwardRange!R2 && (hasLength!R2 || isSomeString!R2));
Replace occurrences of from with to in subject in a new array. If sink is defined, then output the new array into sink.
Parameters:
Sink sink an output range
E[] subject the array to scan
R1 from the item to replace
R2 to the item to replace all instances of from with
Returns:
If sink isn't defined, a new array without changing the contents of subject, or the original array if no match is found.
See Also:
std.algorithm.iteration.map which can act as a lazy replace
Examples:
writeln("Hello Wörld".replace("o Wö", "o Wo")); // "Hello World"
writeln("Hello Wörld".replace("l", "h")); // "Hehho Wörhd"
Examples:
auto arr = [1, 2, 3, 4, 5];
auto from = [2, 3];
auto to = [4, 6];
auto sink = appender!(int[])();

replaceInto(sink, arr, from, to);

writeln(sink.data); // [1, 4, 6, 4, 5]
T[] replace(T, Range)(T[] subject, size_t from, size_t to, Range stuff)
if (isInputRange!Range && (is(ElementType!Range : T) || isSomeString!(T[]) && is(ElementType!Range : dchar)));
Replaces elements from array with indices ranging from from (inclusive) to to (exclusive) with the range stuff.
Parameters:
T[] subject the array to scan
size_t from the starting index
size_t to the ending index
Range stuff the items to replace in-between from and to
Returns:
A new array without changing the contents of subject.
Examples:
auto a = [ 1, 2, 3, 4 ];
auto b = a.replace(1, 3, [ 9, 9, 9 ]);
writeln(a); // [1, 2, 3, 4]
writeln(b); // [1, 9, 9, 9, 4]
void replaceInPlace(T, Range)(ref T[] array, size_t from, size_t to, Range stuff)
if (is(typeof(replace(array, from, to, stuff))));
Replaces elements from array with indices ranging from from (inclusive) to to (exclusive) with the range stuff. Expands or shrinks the array as needed.
Parameters:
T[] array the array to scan
size_t from the starting index
size_t to the ending index
Range stuff the items to replace in-between from and to
Examples:
int[] a = [1, 4, 5];
replaceInPlace(a, 1u, 2u, [2, 3, 4]);
writeln(a); // [1, 2, 3, 4, 5]
replaceInPlace(a, 1u, 2u, cast(int[])[]);
writeln(a); // [1, 3, 4, 5]
replaceInPlace(a, 1u, 3u, a[2 .. 4]);
writeln(a); // [1, 4, 5, 5]
E[] replaceFirst(E, R1, R2)(E[] subject, R1 from, R2 to)
if (isDynamicArray!(E[]) && isForwardRange!R1 && is(typeof(appender!(E[])().put(from[0..1]))) && isForwardRange!R2 && is(typeof(appender!(E[])().put(to[0..1]))));
Replaces the first occurrence of from with to in subject.
Parameters:
E[] subject the array to scan
R1 from the item to replace
R2 to the item to replace from with
Returns:
A new array without changing the contents of subject, or the original array if no match is found.
Examples:
auto a = [1, 2, 2, 3, 4, 5];
auto b = a.replaceFirst([2], [1337]);
writeln(b); // [1, 1337, 2, 3, 4, 5]

auto s = "This is a foo foo list";
auto r = s.replaceFirst("foo", "silly");
writeln(r); // "This is a silly foo list"
E[] replaceLast(E, R1, R2)(E[] subject, R1 from, R2 to)
if (isDynamicArray!(E[]) && isForwardRange!R1 && is(typeof(appender!(E[])().put(from[0..1]))) && isForwardRange!R2 && is(typeof(appender!(E[])().put(to[0..1]))));
Replaces the last occurrence of from with to in subject.
Parameters:
E[] subject the array to scan
R1 from the item to replace
R2 to the item to replace from with
Returns:
A new array without changing the contents of subject, or the original array if no match is found.
Examples:
auto a = [1, 2, 2, 3, 4, 5];
auto b = a.replaceLast([2], [1337]);
writeln(b); // [1, 2, 1337, 3, 4, 5]

auto s = "This is a foo foo list";
auto r = s.replaceLast("foo", "silly");
writeln(r); // "This is a foo silly list"
inout(T)[] replaceSlice(T)(inout(T)[] s, in T[] slice, in T[] replacement);
Creates a new array such that the items in slice are replaced with the items in replacement. slice and replacement do not need to be the same length. The result will grow or shrink based on the items given.
Parameters:
inout(T)[] s the base of the new array
T[] slice the slice of s to be replaced
T[] replacement the items to replace slice with
Returns:
A new array that is s with slice replaced by replacement[].
Examples:
auto a = [1, 2, 3, 4, 5];
auto b = replaceSlice(a, a[1 .. 4], [0, 0, 0]);

writeln(b); // [1, 0, 0, 0, 5]
struct Appender(A) if (isDynamicArray!A);
Implements an output range that appends data to an array. This is recommended over array ~= data when appending many elements because it is more efficient. Appender maintains its own array metadata locally, so it can avoid global locking for each append where capacity is non-zero.
See Also:
Examples:
auto app = appender!string();
string b = "abcdefg";
foreach (char c; b)
    app.put(c);
writeln(app.data); // "abcdefg"

int[] a = [ 1, 2 ];
auto app2 = appender(a);
app2.put(3);
app2.put([ 4, 5, 6 ]);
writeln(app2.data); // [1, 2, 3, 4, 5, 6]
pure nothrow @trusted this(A arr);
Constructs an Appender with a given array. Note that this does not copy the data. If the array has a larger capacity as determined by arr.capacity, it will be used by the appender. After initializing an appender on an array, appending to the original array will reallocate.
pure nothrow @safe void reserve(size_t newCapacity);
Reserve at least newCapacity elements for appending. Note that more elements may be reserved than requested. If newCapacity <= capacity, then nothing is done.
const pure nothrow @property @safe size_t capacity();
Returns:
the capacity of the array (the maximum number of elements the managed array can accommodate before triggering a reallocation). If any appending will reallocate, 0 will be returned.
inout pure nothrow @property @trusted inout(ElementEncodingType!A)[] data();
Returns:
The managed array.
void put(U)(U item)
if (canPutItem!U);
Appends item to the managed array.
void put(Range)(Range items)
if (canPutRange!Range);
Appends an entire range to the managed array.
void opOpAssign(string op : "~", U)(U rhs)
if (__traits(compiles, put(rhs)));
Appends rhs to the managed array.
Parameters:
U rhs Element or range.
pure nothrow @trusted void clear();
Clears the managed array. This allows the elements of the array to be reused for appending.

Note clear is disabled for immutable or const element types, due to the possibility that Appender might overwrite immutable data.

pure @trusted void shrinkTo(size_t newlength);
Shrinks the managed array to the given length.
Throws:
Exception if newlength is greater than the current array length.

Note shrinkTo is disabled for immutable or const element types.

struct RefAppender(A) if (isDynamicArray!A);
A version of Appender that can update an array in-place. It forwards all calls to an underlying appender implementation. Any calls made to the appender also update the pointer to the original array passed in.

Tip Use the arrayPtr overload of appender for construction with type-inference.

Examples:
int[] a = [1, 2];
auto app2 = appender(&a);
writeln(app2.data); // [1, 2]
writeln(a); // [1, 2]
app2 ~= 3;
app2 ~= [4, 5, 6];
writeln(app2.data); // [1, 2, 3, 4, 5, 6]
writeln(a); // [1, 2, 3, 4, 5, 6]

app2.reserve(5);
assert(app2.capacity >= 5);
this(A* arr);
Constructs a RefAppender with a given array reference. This does not copy the data. If the array has a larger capacity as determined by arr.capacity, it will be used by the appender.

Note Do not use built-in appending (i.e. ~=) on the original array until you are done with the appender, because subsequent calls to the appender will reallocate the array data without those appends.

Parameters:
A* arr Pointer to an array. Must not be null.
void opDispatch(string fn, Args...)(Args args)
if (__traits(compiles, (Appender!A a) => mixin("a." ~ fn ~ "(args)")));
Wraps remaining Appender methods such as put.
Parameters:
fn Method name to call.
Args args Arguments to pass to the method.
void opOpAssign(string op : "~", U)(U rhs)
if (__traits(compiles, (Appender!A a) { a.put(rhs); } ));
Appends rhs to the managed array.
Parameters:
U rhs Element or range.
const @property size_t capacity();
Returns the capacity of the array (the maximum number of elements the managed array can accommodate before triggering a reallocation). If any appending will reallocate, capacity returns 0.
inout @property inout(ElementEncodingType!A)[] data();
Returns the managed array.
Appender!A appender(A)()
if (isDynamicArray!A);

Appender!(E[]) appender(A : E[], E)(auto ref A array);
Convenience function that returns an Appender instance, optionally initialized with array.
Examples:
auto w = appender!string;
// pre-allocate space for at least 10 elements (this avoids costly reallocations)
w.reserve(10);
assert(w.capacity >= 10);

w.put('a'); // single elements
w.put("bc"); // multiple elements

// use the append syntax
w ~= 'd';
w ~= "ef";

writeln(w.data); // "abcdef"
RefAppender!(E[]) appender(P : E[]*, E)(P arrayPtr);
Convenience function that returns a RefAppender instance initialized with arrayPtr. Don't use null for the array pointer, use the other version of appender instead.
Examples:
int[] a = [1, 2];
auto app2 = appender(&a);
writeln(app2.data); // [1, 2]
writeln(a); // [1, 2]
app2 ~= 3;
app2 ~= [4, 5, 6];
writeln(app2.data); // [1, 2, 3, 4, 5, 6]
writeln(a); // [1, 2, 3, 4, 5, 6]

app2.reserve(5);
assert(app2.capacity >= 5);