View source code
Display the source code in std/algorithm/iteration.d from which this page was generated on github.
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 local clone.

Function std.algorithm.iteration.joiner

Lazily joins a range of ranges with a separator. The separator itself is a range. If a separator is not provided, then the ranges are joined directly without anything in between them (often called flatten in other languages).

auto joiner(RoR, Separator) (
  RoR r,
  Separator sep
if (isInputRange!RoR && isInputRange!(ElementType!RoR) && isForwardRange!Separator && is(ElementType!Separator : ElementType!(ElementType!RoR)));

auto joiner(RoR) (
  RoR r
if (isInputRange!RoR && isInputRange!(ElementType!RoR));


r An input range of input ranges to be joined.
sep A forward range of element(s) to serve as separators in the joined range.


A range of elements in the joined range. This will be a bidirectional range if both outer and inner ranges of RoR are at least bidirectional ranges. Else if both outer and inner ranges of RoR are forward ranges, the returned range will be likewise. Otherwise it will be only an input range. The range bidirectionality is propagated if no separator is specified.

See also

std.range.chain, which chains a sequence of ranges with compatible elements into a single range.


When both outer and inner ranges of RoR are bidirectional and the joiner is iterated from the back to the front, the separator will still be consumed from front to back, even if it is a bidirectional range too.


import std.algorithm.comparison : equal;
import std.conv : text;

assert(["abc", "def"].joiner.equal("abcdef"));
assert(["Mary", "has", "a", "little", "lamb"]
assert(["", "abc"].joiner("xyz").equal("xyzabc"));
assert(["", ""].joiner("xyz").equal("xyz"));


import std.algorithm.comparison : equal;
import std.range : repeat;

assert(["", ""].joiner.equal(""));
assert(["", "abc"].joiner.equal("abc"));
assert(["abc", ""].joiner.equal("abc"));
assert(["abc", "def"].joiner.equal("abcdef"));
assert(["Mary", "has", "a", "little", "lamb"].joiner.equal("Maryhasalittlelamb"));


joiner allows in-place mutation!

import std.algorithm.comparison : equal;
auto a = [ [1, 2, 3], [42, 43] ];
auto j = joiner(a);
j.front = 44;
writeln(a); // [[44, 2, 3], [42, 43]]
assert(equal(j, [44, 2, 3, 42, 43]));


insert characters fully lazily into a string

import std.algorithm.comparison : equal;
import std.range : chain, cycle, iota, only, retro, take, zip;
import std.format : format;

static immutable number = "12345678";
static immutable delimiter = ",";
auto formatted = number.retro
    .map!(z => chain(z[0].only, z[1] == 2 ? delimiter : null))
static immutable expected = "12,345,678";


joiner can be bidirectional

import std.algorithm.comparison : equal;
import std.range : retro;

auto a = [[1, 2, 3], [4, 5]];
auto j = a.joiner;
j.back = 44;
writeln(a); // [[1, 2, 3], [4, 44]]
assert(equal(j.retro, [44, 4, 3, 2, 1]));


Andrei Alexandrescu


Boost License 1.0.