std.range

Переместиться к: assumeSorted · chain · choose · chooseAmong · Chunks · chunks · Cycle · cycle · drop · dropBack · dropBackExactly · dropBackOne · dropExactly · dropOne · enumerate · EvenChunks · evenChunks · FrontTransversal · frontTransversal · generate · Indexed · indexed · iota · isTwoWayCompatible · Lockstep · lockstep · NullSink · only · padLeft · padRight · radial · Recurrence · recurrence · RefRange · refRange · Repeat · repeat · retro · roundRobin · SearchPolicy · Sequence · sequence · SortedRange · StoppingPolicy · stride · tail · Take · take · takeExactly · takeNone · takeOne · tee · transposed · Transversal · transversal · TransverseOptions · Zip · zip

Этот модуль определяет понятие range (диапазон). Диапазоны обобщают понятия массивов, списков, или чего-нибудь, что включает последовательный доступ. Эта абстракция позволяет использовать один и тот же набор алгоритмов (см. std.algorithm) с обширным рядом различных конкретных типов. Например, линейный алгоритм поиска, такой как, std.algorithm.find работает не только для массивов, но и для связанных списков, входных файлов, поступающих данных по сети и т.д. Смотрите так же tutorial on ranges Ali Çehreli's для изучения основ работы с ними и создания кода, основанного на диапазонах.
Для более подробной информации о точке зрения на основную идею диапазонов и мотивации, стоящей за ними, смотрите статью Andrei Alexandrescu's On Iteration.

Подмодули: Этот модуль имеет два подмодуля:

Подмодуль std.range.primitives предоставляет базовую функциональность диапазона. Он определяет несколько шаблонов для тестирования данного объекта — является ли он диапазоном, какого типа диапазоном, и предоставляет несколько общих операций с дипазонами.
Подмодуль std.range.interfaces предоставляет основанные на объектах интерфейсы для работы с диапазонами через полиморфизм времени выполнения.
Остальная часть этого модуля предоставляет богатый набор шаблонов создания и композиции диапазонов, что позволит вам создавать новые диапазоны из существующих диапазонов:
chain Сцепляет несколько диапазонов в один диапазон.
choose Выбирает один из двух диапазонов во время выполнения на основе логического условия.
chooseAmong Выбирает один из нескольких диапазонов во время выполнения на основе индекса.
chunks Создает диапазон, который возвращает куски исходного диапазона фиксированного размера.
cycle Создает бесконечный диапазон, который повторяет данный лидирующий диапазон бесконечно. Хорошо для реализации кольцевых буферов.
drop Создает диапазон, который остаётся при отбрасывании n первых элементов из данного диапазона.
dropExactly Создает диапазон, который получается в результате отбрасывания ровно n первых элементов из данного диапазона.
dropOne Создает диапазон, который получается в результате отбрасывания первого элемента из данного диапазона.
enumerate Итерирует диапазон с прикрепленной индексной переменной.
evenChunks Создает диапазон, который возвращает несколько кусков приблизительно равной длины из первоначального диапазона.
frontTransversal Создает диапазон, который итерирует над первыми элементами данных диапазонов.
indexed Создаёт диапазон, который открывает вид на данный диапазон, как если бы его элементы были переупорядочены в соответствии с заданным диапазоном индексов.
iota Создает диапазон, состоящий из чисел между начальной и конечной точками, на расстоянии заданного интервала друг от друга.
lockstep Итерирует n диапазонов в жесткой конфигурации, для использования в цикле foreach. Похоже на zip, за исключением того, что lockstep разработан специально для циклов foreach.
NullSink Выходной диапазон, который отбрасывает данные, которые он получает.
only Создаёт диапазон, который итерирует над данными аргументами.
padLeft Заполняет диапазон до заданной длины путем добавления данного элемента в передней части диапазона. Ленив, если диапазон имеет известную длину.
padRight Лениво заполняет диапазон до определённой длины, добавляя данный элемент к концу диапазона.
radial Дан диапазон с произвольным доступом и стартовая точка, создаёт диапазон, который поочерёдно возвращает следующий левый и следующий правый элемент от стартовой точки.
recurrence Создаёт лидирующий диапазон, значения которого определяются математическим рекуррентным соотношением.
repeat Создаёт диапазон, который состоит из единственного элемента, повторенного n раз, или бесконечный дипазон, повторяющий этот элемент бесконечно.
retro Итерирует двунаправленный диапазон в обратную сторону.
roundRobin Дано n диапазонов, создается новый диапазон, который возвращает n первых элементов каждого дипазона, по очереди, затем второй элемент каждого дипазона, и так далее, циклически.
sequence Подобно recurrence, за исключением того, что создаётся диапазон с произвольным доступом.
stride Итерирует диапазон с шагом n.
tail Возвращает диапазон, предоставляющий n элементов конца данного диапазона.
take Создаёт под-диапазон, состоящий из первых элементов данного дипазона, в количестве до n штук.
takeExactly Подобно take, но исходит из того, что переданный диапазон действительно имеет n элементов, и следовательно, также определяет свойство длины length.
takeNone Создаёт диапазон с произвольный доступом, состоящий из нуля элементов данного диапазона.
takeOne Создаёт диапазон с произвольный доступом, состоящий из не более, чем одного, первого элемента данного дипазона.
tee Создаёт диапазон, который завертывает данный диапазон, и пересылает его элементы, одновременно также вызывает заданную функцию с каждым элементом.
transposed Транспонирует диапазон диапазонов.
transversal Создаёт диапазон, который итерирует над n-ными элементами диапазонов с произвольным доступом.
zip Дано n диапазонов, создаёт диапазон, который последовательно возвращает кортеж всех первых элементов, кортеж всех вторых элементов, и т.д.
Диапазоны, чьи элементы отсортированы, имеют возможность быть эффективнее с определёнными операциями. Для этого, можно использовать функцию assumeSorted для создания SortedRange из заранее отсортированного диапазона. Функция std.algorithm.sorting.sort также очень кстати возвращает SortedRange. Объекты SortedRange предоставляют некоторые дополнительные операции с диапазонами, которые используют тот факт, что диапазон отсортирован.

Исходный код: std/range/package.d

Лицензия:
Boost License 1.0.
Авторы:
Andrei Alexandrescu, David Simcha, Jonathan M Davis, and Jack Stouffer. Credit for some of the ideas in building this module goes to Leonardo Maffi.
auto retro(Range)(Range r)
if (isBidirectionalRange!(Unqual!Range));
Итерирует двунаправленный диапазон в обратном порядке. Первоначальный диапазон может быть доступен через свойство source. Применение retro дважды на том же диапазоне даст исходный диапазон.
Параметры:
Range r двунаправленный диапазон, который нужно итерировать в обратную сторону
Возвращает:
Двунаправленный диапазон с длиной, если r также предоставляет длину. Или, если r — диапазон с произвольным доступом, тогда возвращаемая величина также будет иметь произвольный доступ.
Примеры:
import std.algorithm.comparison : equal;
int[] a = [ 1, 2, 3, 4, 5 ];
assert(equal(retro(a), [ 5, 4, 3, 2, 1 ][]));
assert(retro(a).source is a);
assert(retro(retro(a)) is a);
auto stride(Range)(Range r, size_t n)
if (isInputRange!(Unqual!Range));
Итерирует диапазон r с шагом n. Если диапазон r — это диапазон с произвольным доступом, перемещения производятся с помощью индексов в диапазоне; в противном случае перемещения производятся через последовательные вызовы popFront. Применение stride дважды к тому же диапазону даст результат stride с шагом, равным произведению двух применений. Если n равно 0, это приводит к ошибке.
Параметры:
Range r входной диапазон, к которому применяется stride
size_t n количество пропускаемых элементов
Возвращает:
Как минимум, входной диапазон. Результирующий диапазон принимает примитивы базового диапазона так долго, пока std.range.primitives.hasLength является истиной.
Примеры:
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 ][]));
assert(stride(stride(a, 2), 3) == stride(a, 6));
auto chain(Ranges...)(Ranges rs)
if (Ranges.length > 0 && allSatisfy!(isInputRange, staticMap!(Unqual, Ranges)) && !is(CommonType!(staticMap!(ElementType, staticMap!(Unqual, Ranges))) == void));
Соединяет множество диапазонов в последовательность. Функция chain принимает любое количество диапазонов и возвращает объект Chain!(R1, R2,...). Диапазоны могут быть различными, но они должны иметь один и тот же тип элемента. Результат является диапазоном, в котором есть примитивы front, popFront, и empty. Если во всех диапазонах есть произвольный доступ и length, Chain также их предоставит.
Если только один диапазон направлен в Chain или chain, тип Chain становится псевдонимом непосредственно самого этого типа диапазона.
Параметры:
Ranges rs входные диапазоны, которые надо соединить вместе
Возвращает:
Как минимум, входной диапазон. Если все диапазоны в rs предоставляют примитив диапазона, возвращаемый диапазон также предоставит этот примитив диапазона.
Примеры:
import std.algorithm.comparison : equal;

int[] arr1 = [ 1, 2, 3, 4 ];
int[] arr2 = [ 5, 6 ];
int[] arr3 = [ 7 ];
auto s = chain(arr1, arr2, arr3);
assert(s.length == 7);
assert(s[5] == 6);
assert(equal(s, [1, 2, 3, 4, 5, 6, 7][]));
Примеры:
Примитивы диапазона переносятся на возвращаемый диапазон, если все диапазоны их предоставляют
import std.algorithm.sorting : sort;
import std.algorithm.comparison : equal;

int[] arr1 = [5, 2, 8];
int[] arr2 = [3, 7, 9];
int[] arr3 = [1, 4, 6];

// сортировка на-месте во всех массивах
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]));
auto choose(R1, R2)(bool condition, R1 r1, R2 r2)
if (isInputRange!(Unqual!R1) && isInputRange!(Unqual!R2) && !is(CommonType!(ElementType!(Unqual!R1), ElementType!(Unqual!R2)) == void));
Выбор одного из двух диапазонов во время выполнения в зависимости от логического условия condition.
Диапазоны могут быть различными, но они должны иметь совместимые типы элементов (то есть, CommonType должен существовать для обоих типов элементов). Результат является диапазоном, который предлагает самые слабые возможности из двух (например, ForwardRange, если R1— диапазон с произвольным доступом и R2 — лидирующий диапазон).
Параметры:
bool condition какой диапазон выбрать: r1 если true, r2 иначе
R1 r1 "true" диапазон
R2 r2 "false" диапазон
Возвращает:
Тип диапазона, зависимый от R1 и 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() в основном полезна, когда вам нужно выбрать один из двух диапазонов
// с различными типами во время выполнения.
static assert(!is(typeof(data1) == typeof(data2)));

auto chooseRange(bool pickFirst)
{
    // Возвращаемый диапазон является обёртывающим общим типом, который может быть использован
    // для возврата или хранения обоих диапазонов, не встречая ошибку типа.
    return choose(pickFirst, data1, data2);

    // Простое возвращение выбранного диапазона, без использования choose(),
    // не работает, поскольку map() и filter() возвращают различные типы.
    //return pickFirst ? data1 : data2; // не компилируется
}

auto result = chooseRange(true);
assert(result.equal([ 1, 2, 4 ]));

result = chooseRange(false);
assert(result.equal([ 6, 7, 8, 9 ]));
auto chooseAmong(Ranges...)(size_t index, Ranges rs)
if (Ranges.length > 2 && is(typeof(choose(true, rs[0], rs[1]))) && is(typeof(chooseAmong(0, rs[1..$]))));

auto chooseAmong(Ranges...)(size_t index, Ranges rs)
if (Ranges.length == 2 && is(typeof(choose(true, rs[0], rs[1]))));
Выбор одного из нескольких диапазонов во время выполнения.
Диапазоны могут быть различными, но они должны иметь совместимые типы элементов. Результат является диапазоном, который предлагает самые слабые возможности из всех диапазонов.
Параметры:
size_t index какой диапазон выбрать, должно быть меньше, чем количество диапазонов
Ranges rs два или более диапазонов
Возвращает:
Диапазон, соответсвующий номеру индекса. Если rs состоит только из одного диапазона, возвращаемый тип является псевдонимом типа этого диапазона.
Примеры:
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;
    assert(s.length == 4);
    assert(s[2] == 3);
    s.popFront();
    assert(equal(t, [1, 2, 3, 4][]));
}
{
    auto s = chooseAmong(1, arr1, arr2, arr3);
    assert(s.length == 2);
    s.front = 8;
    assert(equal(s, [8, 6][]));
}
{
    auto s = chooseAmong(1, arr1, arr2, arr3);
    assert(s.length == 2);
    s[1] = 9;
    assert(equal(s, [8, 9][]));
}
{
    auto s = chooseAmong(1, arr2, arr1, arr3)[1..3];
    assert(s.length == 2);
    assert(equal(s, [2, 3][]));
}
{
    auto s = chooseAmong(0, arr1, arr2, arr3);
    assert(s.length == 4);
    assert(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);
    assert(c[3] == 9);
    c[3] = 42;
    assert(c[3] == 42);
    assert(c.moveFront() == 6);
    assert(c.moveBack() == 10);
    assert(c.moveAt(4) == 10);
}
{
    import std.range : cycle;
    auto s = chooseAmong(1, cycle(arr2), cycle(arr3));
    assert(isInfinite!(typeof(s)));
    assert(!s.empty);
    assert(s[100] == 7);
}
auto roundRobin(Rs...)(Rs rs)
if (Rs.length > 1 && allSatisfy!(isInputRange, staticMap!(Unqual, Rs)));
roundRobin(r1, r2, r3) производит r1.front, затем r2.front, затем r3.front, после чего выталкивает по одному элементу из каждого, и снова продолжает с r1. Например, если два диапазона включены, он поочередно даёт элементы из двух диапазонов. roundRobin останавливается после того, как поглотит все диапазоны (пропуская те, что завершились раньше).
Примеры:
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 можно использовать для создания функциональности "чередования", которая вставляет элемент между каждым из элементов в диапазоне.
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]));
auto radial(Range, I)(Range r, I startingIndex)
if (isRandomAccessRange!(Unqual!Range) && hasLength!(Unqual!Range) && isIntegral!I);

auto radial(R)(R r)
if (isRandomAccessRange!(Unqual!R) && hasLength!(Unqual!R));
Итерирует диапазон с произвольным доступом, начиная с данной точки и прогрессивно расширяя влево и вправо от этой точки. Если не задано никакой начальной точки, итерация начинается с середины диапазона. Итерация охватывает весь диапазон.
Когда startingIndex равен 0, диапазон полностью будет итерирован в прямом порядке, и в обратном порядке, если передано r.length.
Параметры:
Range r диапазон с произвольным доступом с длиной и извлечением среза
I startingIndex индекс, с которого начинать итерацию
Возвращает:
Лидирующий диапазон с длиной
Примеры:
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 ]));

// Если левый конец достигнут первым, остальные элементы 
// справа сцепляются в порядке:
a = [ 0, 1, 2, 3, 4, 5 ];
assert(equal(radial(a, 1), [ 1, 2, 0, 3, 4, 5 ]));

// Если правый конец достигнут первым, остальные элементы
// слева сцепляются в обратном порядке:
assert(equal(radial(a, 4), [ 4, 5, 3, 2, 1, 0 ]));

Переместиться к: 2 · back · empty · front · length · maxLength · moveAt · moveBack · moveFront · opDollar · opIndex · opIndexAssign · opSlice · popBack · popFront · save · source

struct Take(Range) if (isInputRange!(Unqual!Range) && !(!isInfinite!(Unqual!Range) && hasSlicing!(Unqual!Range) || is(Range T == Take!T)));

Переместиться к: 2

Take!R take(R)(R input, size_t n)
if (isInputRange!(Unqual!R) && !isInfinite!(Unqual!R) && hasSlicing!(Unqual!R) && !is(R T == Take!T));
Лениво принимает только вплоть до n элементов диапазона. Это особенно полезно при использовании с бесконечными диапазонами.
В отличие от takeExactly, take не требует наличия n или больше элементов в r. Как следствие, информация о длине отсутствует в результирующем диапазоне, если r также не имеет информацию о длине.
Параметры:
r входной диапазон, по которому надо итерировать вплоть до n раз
size_t n количество требуемых элементов
Возвращает:
Как минимум, входной диапазон. Если диапазон предлагает произвольный доступ и длину, take их также предложит.
R source;
Доступ пользователей на чтение и запись
@property bool empty();

Переместиться к: 2

@property ref auto front();

void popFront();

@property Take save();

@property auto front(ElementType!R v);

auto moveFront();

const @property size_t length();

alias opDollar = length;

auto opSlice()(size_t i, size_t j)
if (hasSlicing!R);

void popBack();

Переместиться к: 2

@property ref auto back();

ref auto opIndex(size_t index);

@property auto back(ElementType!R v);

void opIndexAssign(ElementType!R v, size_t index);

auto moveBack();

auto moveAt(size_t index);
Примитивы диапазона
const @property size_t maxLength();
Доступ к максимальной длине дипазона.

Замечание: фактическая длина диапазона зависит от диапазона, лежащего в основе. Если он имеет меньше элементов, он остановится прежде, чем maxLength будет достигнут.

template Take(R) if (isInputRange!(Unqual!R) && (!isInfinite!(Unqual!R) && hasSlicing!(Unqual!R) || is(R T == Take!T)))

Take!R take(R)(R input, size_t n)
if (is(R T == Take!T));

Take!R take(R)(R input, size_t n)
if (isInputRange!(Unqual!R) && (isInfinite!(Unqual!R) || !hasSlicing!(Unqual!R) && !is(R T == Take!T)));
Этот шаблон просто псевдоним самого R и полезен для согласованности общего кода.
Примеры:
import std.algorithm.comparison : equal;

int[] arr1 = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ];
auto s = take(arr1, 5);
assert(s.length == 5);
assert(s[4] == 5);
assert(equal(s, [ 1, 2, 3, 4, 5 ][]));
Примеры:
Если диапазон заканчивается до n элементов, take просто возвращает весь диапазон (в отличие от takeExactly, который повлечет за собой ошибки, если диапазон заканчивается преждевременно):
import std.algorithm.comparison : equal;

int[] arr2 = [ 1, 2, 3 ];
auto t = take(arr2, 5);
assert(t.length == 3);
assert(equal(t, [ 1, 2, 3 ]));
auto takeExactly(R)(R range, size_t n)
if (isInputRange!R);
Похоже на take, но допускает, что диапазон имеет по крайней мере n элементов. Следовательно, результат takeExactly(range, n) всегда определяет свойство length (и инициализирует его на n), даже когда сам диапазон не определяет длину length.
Результат takeExactly идентичен тому же самому take в случаях, где исходный диапазон определяет длину или он бесконечен.
Тем не менее, в отличие от take, недопустимо передавать диапазон менее чем с n элементами в takeExactly; это вызовет ошибку.
Примеры:
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));
assert(b.length == 3);
assert(b.front == 1);
assert(b.back == 3);
auto takeOne(R)(R source)
if (isInputRange!R);
Возвращает диапазон, в котором самое большее один элемент; например, takeOne([42, 43, 44]) возвращает диапазон, состоящий из целого 42. Вызов popFront() для этого диапазона делает его пустым.
По эффекту takeOne(r) отчасти эквивалентен take(r, 1), но для некоторых интерфейсов важно статически знать, что диапазон может иметь самое большее один элемент.
Тип возвращаемый takeOne — диапазон с произвольным доступом с длиной независимо от возможностей R (другая возможность, которая отличает takeOne от take).
Примеры:
auto s = takeOne([42, 43, 44]);
static assert(isRandomAccessRange!(typeof(s)));
assert(s.length == 1);
assert(!s.empty);
assert(s.front == 42);
s.front = 43;
assert(s.front == 43);
assert(s.back == 43);
assert(s[0] == 43);
s.popFront();
assert(s.length == 0);
assert(s.empty);

Переместиться к: 2

auto takeNone(R)()
if (isInputRange!R);
Возвращает пустой диапазон, о котором статически известно, что он будет пустым, и гарантируется, что у него будет length и произвольный доступ независимо от возможностей R.
Примеры:
auto range = takeNone!(int[])();
assert(range.length == 0);
assert(range.empty);
auto takeNone(R)(R range)
if (isInputRange!R);
Создаёт пустой диапазон из данного диапазона за время Ο(1). Если возможно, возвращается диапазон того же типа. Если нет, возвращается 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);
auto tail(Range)(Range range, size_t n)
if (isInputRange!Range && !isInfinite!Range && (hasLength!Range || isForwardRange!Range));
Возвращает диапазон, предоставляющий до n элементов конца range.
Задуман как диапазонный эквивалент утилиты tail (хвост) в Unix. Когда длина range меньше чем или равна n, range возвращается как есть.
Выполняется за Ο(1) шагов для диапазонов, которые поддерживают срезы и имеют длину. Завершается за время Ο(range.length) для всех остальных диапазонов.
Параметры:
Range range диапазон, у которого надо получить хвост
size_t n максимальное количество элементов, включаемых в хвост
Возвращает:
Возвращает хвост диапазона, расширенный информацией о длине
Примеры:
// tail -c n
assert([1, 2, 3].tail(1) == [3]);
assert([1, 2, 3].tail(2) == [2, 3]);
assert([1, 2, 3].tail(3) == [1, 2, 3]);
assert([1, 2, 3].tail(4) == [1, 2, 3]);
assert([1, 2, 3].tail(0).length == 0);

// tail --lines=n
import std.algorithm.comparison : equal;
import std.algorithm.iteration : joiner;
import std.string : lineSplitter;

assert("one\ntwo\nthree"
        .lineSplitter
        .tail(2)
        .joiner("\n")
        .equal("two\nthree"));
R drop(R)(R range, size_t n)
if (isInputRange!R);

R dropBack(R)(R range, size_t n)
if (isBidirectionalRange!R);
Удобная функция, которая вызывает range.popFrontN(n) и возвращает range. drop облегчает выталкивание элементов из диапазона и последующую передачу его в другую функцию внутри единственного выражения, поскольку popFrontN потребует нескольких операторов.
dropBack предоставляет ту же функциональность, но вызывает range.popBackN(n).

Замечание: drop и dropBack будет выталкивать вплоть до n элементов, но остановится, если range опустеет раньше.

Примеры:
import std.algorithm.comparison : equal;

assert([0, 2, 1, 5, 0, 3].drop(3) == [5, 0, 3]);
assert("hello world".drop(6) == "world");
assert("hello world".drop(50).empty);
assert("hello world".take(6).drop(3).equal("lo "));
R dropExactly(R)(R range, size_t n)
if (isInputRange!R);

R dropBackExactly(R)(R range, size_t n)
if (isBidirectionalRange!R);
Аналогично drop и dropBack, но они вызывают range.popFrontExactly(n) и range.popBackExactly(n).

Замечание: В отличие от drop, dropExactly исходит из того, что диапазон range содержит по крайней мере n элементов. Это делает dropExactly быстрее чем drop, но это также означает, что если диапазон не содержит по крайней мере n элементов, произойдёт попытка вызывать popFront на пустом диапазоне, что приведёт к неопределенному поведению. Так что используйте popFrontExactly только когда гарантируется, что диапазон имеет по крайней мере n элементов.

Параметры:
R range входной диапазон, из которого надо отбросить
size_t n количество выбрасываемых элементов
Возвращает:
range с отброшенными n элементами
Примеры:
import std.algorithm.comparison : equal;
import std.algorithm.iteration : filterBidirectional;

auto a = [1, 2, 3];
assert(a.dropExactly(2) == [3]);
assert(a.dropBackExactly(2) == [1]);

string s = "日本語";
assert(s.dropExactly(2) == "語");
assert(s.dropBackExactly(2) == "日");

auto bd = filterBidirectional!"true"([1, 2, 3]);
assert(bd.dropExactly(2).equal([3]));
assert(bd.dropBackExactly(2).equal([1]));
R dropOne(R)(R range)
if (isInputRange!R);

R dropBackOne(R)(R range)
if (isBidirectionalRange!R);
Удобная функция, которая вызывает range.popFront() и возвращает range. dropOne упрощает выталкивание элемента из диапазона и последующую передачу его в другую функцию внутри единственного выражения, поскольку popFront потребует нескольких операторов.
dropBackOne предоставляет ту же функциональность, но вызывает 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];
assert(a.dropOne() == [2, 3]);
assert(a.dropBackOne() == [1, 2]);

string s = "日本語";
assert(s.dropOne() == "本語");
assert(s.dropBackOne() == "日本");

auto bd = filterBidirectional!"true"([1, 2, 3]);
assert(bd.dropOne().equal([2, 3]));
assert(bd.dropBackOne().equal([1, 2]));

Переместиться к: back · empty · front · opDollar · opIndex · opSlice · popBack · popFront · save

struct Repeat(T);

Переместиться к: 2

Repeat!T repeat(T)(T value);
Создать диапазон, который всегда повторяет value.
Параметры:
T value величина для повторения
Возвращает:
Бесконечный диапазон с произвольным доступом и поддержкой срезов.
Примеры:
import std.algorithm.comparison : equal;

assert(equal(5.repeat().take(4), [ 5, 5, 5, 5 ]));
inout @property inout(T) front();

inout @property inout(T) back();

enum bool empty;

void popFront();

void popBack();

inout @property auto save();

inout inout(T) opIndex(size_t);

Переместиться к: 2

auto opSlice(size_t i, size_t j);

enum auto opDollar;

inout auto opSlice(size_t, DollarToken);
Примитивы диапазона
Take!(Repeat!T) repeat(T)(T value, size_t n);
Повторять value точно n раз. Эквивалент take(repeat(value), n).
Примеры:
import std.algorithm.comparison : equal;

assert(equal(5.repeat(4), 5.repeat().take(4)));
auto generate(Fun)(Fun fun)
if (isCallable!fun);

auto generate(alias fun)()
if (isCallable!fun);
Даётся вызываемая (std.traits.isCallable) fun, создаётся диапазон, front которого определяется последовательными вызовами для fun(). Особенно полезно вызывать функцию с глобальными побочными эффектами (случайными функциями), или для создания диапазонов, выраженных как единственный делегат, а не целый структура front/popFront/empty. fun может быть передана также параметром псевдонима шаблона (существующие функции, делегаты, структуры с заданным static opCall) или величиной времени выполнения (делегат, объект функции). Результирующий диапазон моделирует InputRange (входной диапазон, std.range.primitives.isInputRange). Результирующий диапазон будет вызывать fun() при конструировании, и каждом вызове popFront, и при вызове front будет возвращаться кешированная величина.
Возвращает:
inputRange, где каждый элемент представляет новый вызов 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;

//Возвращает делегат времени выполнения
auto infiniteIota(T)(T low, T high)
{
    T i = high;
    return (){if (i == high) i = low; return i++;};
}
//приспособлен как диапазон.
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);

Переместиться к: 2 · empty · front · opDollar · opIndex · opIndexAssign · opSlice · popFront · save · this

struct Cycle(R) if (isForwardRange!R && !isInfinite!R);

template Cycle(R) if (isInfinite!R)
Повторяет данный лидирующий диапазон до бесконечности. Если исходный диапазон бесконечен (фактически, применение к нему Cycle ничего не меняет), Cycle обнаруживает это и выводит псевдоним исходного диапазона. Если исходный диапазон имеет произвольный доступ, Cycle предоставляет произвольный доступ и также предлагает конструктор, принимающий индекс начальной позиции index. Cycle работает со статическими массивами в дополнение к диапазонам, в основном из соображений производительности.

Замечание: Входной диапазон не должен быть пустым.

Совет: Это отличный способ реализации простых кольцевых буферов.

Переместиться к: 2

this(R input, size_t index = 0);

Переместиться к: 2

@property ref auto front();

const @property ref auto front();

@property auto front(ElementType!R val);

Переместиться к: 2

enum bool empty;

Переместиться к: 2

void popFront();

Переместиться к: 2

ref auto opIndex(size_t n);

const ref auto opIndex(size_t n);

auto opIndexAssign(ElementType!R val, size_t n);

Переместиться к: 2

@property Cycle save();

Переместиться к: 2

enum auto opDollar;

Переместиться к: 2

auto opSlice(size_t i, size_t j);

auto opSlice(size_t i, DollarToken);
Примитивы диапазона
struct Cycle(R) if (isStaticArray!R);

Cycle!R cycle(R)(R input)
if (isForwardRange!R && !isInfinite!R);

Cycle!R cycle(R)(R input, size_t index = 0)
if (isRandomAccessRange!R && !isInfinite!R);

Cycle!R cycle(R)(R input)
if (isInfinite!R);

@system Cycle!R cycle(R)(ref R input, size_t index = 0)
if (isStaticArray!R);
Примеры:
import std.algorithm.comparison : equal;
import std.range : cycle, take;

// Здесь мы создаём бесконечную циклическую последовательность из [1, 2]
// (т.е. получится [1, 2, 1, 2, 1, 2 и так далее]), затем
// берём 5 элементов этой последовательности (итак, мы имеем [1, 2, 1, 2, 1])
// и сравниваем это с ожидаемыми величинами.
assert(cycle([1, 2]).take(5).equal([ 1, 2, 1, 2, 1 ]));
@system this(ref R input, size_t index = 0);

inout @property ref @safe inout(ElementType) front();

enum bool empty;

@safe void popFront();

inout ref @safe inout(ElementType) opIndex(size_t n);

inout @property @safe inout(Cycle) save();

enum auto opDollar;

@safe auto opSlice(size_t i, size_t j);

inout @safe inout(typeof(this)) opSlice(size_t i, DollarToken);
Примитивы диапазона

Переместиться к: back · empty · front · length · moveAt · moveBack · moveFront · opDollar · opIndex · opIndexAssign · opSlice · popBack · popFront · save · this

struct Zip(Ranges...) if (Ranges.length && allSatisfy!(isInputRange, Ranges));

auto zip(Ranges...)(Ranges ranges)
if (Ranges.length && allSatisfy!(isInputRange, Ranges));

auto zip(Ranges...)(StoppingPolicy sp, Ranges ranges)
if (Ranges.length && allSatisfy!(isInputRange, Ranges));
Итерирует несколько диапазонов ranges по порядку. Тип элемента является прокси-кортежем, который позволяет получить доступ к текущему элементу в n-ом диапазоне, используя e[n].
zip подобен lockstep, но lockstep не связывает в набор свои элементы и использует протокол opApply. lockstep даёт ссылку на доступ к элементам в цикле foreach.
Параметры:
StoppingPolicy sp управляет, как zip поступит, если диапазоны имеют различные длины
Ranges ranges диапазоны, которые zip объединит
Возвращает:
Как минимум, входной дипазон. Zip предоставляет возможности самого низкого диапазона для всех компонентов, например, он предоставляет произвольный доступ тогда и только тогда, когда все диапазоны поддерживают произвольный доступ, и также предоставляет мутацию и swapping, если все диапазоны предлагают их. В связи с этим, Zip является чрезвычайно мощным, поскольку он позволяет манипулировать несколькими диапазонами синхронно.
Исключения:
Срабатывает исключение, если не все диапазоны имеют одинаковую длину, и sp установлен на StoppingPolicy.requireSameLength.
Примеры:
import std.algorithm.comparison : equal;
import std.algorithm.iteration : map;

// попарные суммы
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];
}

assert(result == [ "1a", "2b", "3c" ]);

size_t idx = 0;
// распаковка элементов кортежа с помощью foreach
foreach (e1, e2; zip(a, b))
{
    assert(e1 == a[idx]);
    assert(e2 == b[idx]);
    ++idx;
}
Примеры:
zip является мощным — следующий код сортирует два массива параллельно:
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]);

assert(a == [ 3, 2, 1 ]);
// b отсортирован соответственно сортировке a
assert(b == [ "b", "c", "a" ]);
this(R rs, StoppingPolicy s = StoppingPolicy.shortest);
Строит объект. Обычно вызывается косвенно через использование функции zip.
enum bool empty;
Возвращает true , если диапазон дошел до конца. Тест зависит от политики остановки (stopping policy).
@property Zip save();

Переместиться к: 2

@property ElementType front();
Возвращает текущий элемент итерации.
@property void front(ElementType v);
Устанавливает front всех итерируемых диапазонов.
ElementType moveFront();
Переместиться к началу.

Переместиться к: 2

@property ElementType back();
Возвращает самый правый элемент.
ElementType moveBack();
Переместиться к концу.
Возвращает самый правый элемент.
@property void back(ElementType v);
Returns the current iterated element.
Возвращает самый правый элемент.
void popFront();
Переход к следующему элементу во всех контролируемых диапазонах.
void popBack();
Вызывает popBack во всех контролируемых диапазонах.
@property auto length();
Возвращает length для диапазона. Определено, только если для всех диапазонов определён length.
alias opDollar = length;
Возвращает длину для диапазона. Определено, только если для всех диапазонов определён length.
auto opSlice(size_t from, size_t to);
Возвращает срез диапазона. Определено, только если для всех диапазонов определены операции извлечения среза.
ElementType opIndex(size_t n);
Возвращает n-й элемент составного диапазона. Определено, только если для всех диапазонов определен произвольный доступ.
void opIndexAssign(ElementType v, size_t n);
Присваивает n-й элемент составного диапазона. Определено, только если для всех диапазонов определен произвольный доступ.
Возвращает n-й элемент составного диапазона. Определено, только если для всех диапазонов определен произвольный доступ.
ElementType moveAt(size_t n);
Считывает с потерей n-й элемент составного диапазона. Определено, только если для всех диапазонов определен произвольный доступ.
Возвращает n-й элемент составного диапазона. Определено, только если для всех диапазонов определен произвольный доступ.

Переместиться к: longest · requireSameLength · shortest

enum StoppingPolicy: int;
Определяет, когда итерации в Zip должны остановиться. По умолчанию остановка в конце самого короткого из всех диапазонов.
shortest
Остановить, когда исчерпается самый короткий диапазон
longest
Остановить, когда исчерпается самый длинный диапазон
requireSameLength
Потребовать, чтобы все диапазоны были равными

Переместиться к: this

struct Lockstep(Ranges...) if (Ranges.length > 1 && allSatisfy!(isInputRange, Ranges));

Lockstep!Ranges lockstep(Ranges...)(Ranges ranges)
if (allSatisfy!(isInputRange, Ranges));

Lockstep!Ranges lockstep(Ranges...)(Ranges ranges, StoppingPolicy s)
if (allSatisfy!(isInputRange, Ranges));
Итерирует несколько диапазонов синхронно, с использованием цикла foreach. В отличие от zip, он даёт ссылки на доступ к своим элементам. Если передан только единственный диапазон, Lockstep выводит наружу псевдоним на него. Если у диапазонов различные длины и s == StoppingPolicy.shortest , остановка происходит после того, как самый короткий диапазон станет пустым. Если у диапазонов различные длины и s == StoppingPolicy.requireSameLength, бросается исключение. s не может быть StoppingPolicy.longest, и его передача вызывает исключение.
Итерирование над Lockstep в обратном порядке и с индексом возможны только тогда, когда s == StoppingPolicy.requireSameLength, чтобы сохранять индексы. Если попытаться итерировать в обратном порядке при s == StoppingPolicy.shortest, будет брошено исключение.
По умолчанию, StoppingPolicy устанавливается в StoppingPolicy.shortest.
Смотрите также:
zip
lockstep похож на zip, но zip объединяет свои элементы и возвращает диапазон. lockstep также поддерживает доступ по ссылке. Используйте zip, если вы хотите передать результат в функцию диапазона.
Примеры:
auto arr1 = [1,2,3,4,5,100];
auto arr2 = [6,7,8,9,10];

foreach (ref a, b; lockstep(arr1, arr2))
{
    a += b;
}

assert(arr1 == [7,9,11,13,15,100]);

/// Lockstep также поддерживает цикл с индексной переменной:
foreach (index, a, b; lockstep(arr1, arr2))
{
    assert(arr1[index] == a);
    assert(arr2[index] == b);
}
this(R ranges, StoppingPolicy sp = StoppingPolicy.shortest);
struct Recurrence(alias fun, StateType, size_t stateSize);

Recurrence!(fun, CommonType!State, State.length) recurrence(alias fun, State...)(State initial);
Создает математическую последовательность, получая начальные значения и рекуррентную функцию, которая вычисляет следующее значение из существующих. Формой последовательности будет бесконечный лидирующий диапазон. Сам тип Recurrence редко используется непосредственно; чаще всего, рекуррентные последовательности получают через вызов функции recurrence.
При вызове recurrence, функция, которая вычисляет следующее значение, задаётся как аргумент шаблона, а начальные значения initial в recurrence передаются как обычные аргументы. Например, в последовательности Фибоначчи есть два начальных значения (и, следовательно, размер state равен 2), поскольку для вычисления следующего значения Фибоначчи нужно два предыдущих значения.
Сигнатурой этой функции должно быть:
auto fun(R)(R state, size_t n)
где n будет индексом текущего значения, а state будет непонятным вектором состояния, который может быть проиндексирован с помощью нотации индексов массива state[i], где допустимые значения i находятся в пределах от (n - 1) до (n - State.length).
Если функция передаётся в форме строки, состояние state имеет имя "a" , а начинающийся с нуля индекс в recurrence имеет имя "n". Данная строка должна возвращать искомую величину для a[n], получая a[n - 1], a[n - 2], a[n - 3],..., a[n - stateSize]. Размер состояния stateSize диктуется количеством аргументов, передаваемых для вызова в recurrence. Сама структура Recurrence заботится об управлении рекуррентным состоянием и сдвигает его соответствующим образом.
Примеры:
import std.algorithm.comparison : equal;

// Числа Фибоначчи, с использованием функции в форме строки:
// a[0] = 1, a[1] = 1, и вычисляется a[n+1] = a[n-1] + a[n]
auto fib = recurrence!("a[n-1] + a[n-2]")(1, 1);
assert(fib.take(10).equal([1, 1, 2, 3, 5, 8, 13, 21, 34, 55]));

// Факториалы, с использованием функции в лямбда-форме:
auto fac = recurrence!((a,n) => a[n-1] * n)(1);
assert(take(fac, 10).equal([
    1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880
]));

// Треугольные числа, с использованием функции в явной форме:
static size_t genTriangular(R)(R state, size_t n)
{
    return state[n-1] + n;
}
auto tri = recurrence!genTriangular(0);
assert(take(tri, 10).equal([0, 1, 3, 6, 10, 15, 21, 28, 36, 45]));
struct Sequence(alias fun, State);

auto sequence(alias fun, State...)(State args);
Sequence (последовательность) похожа на Recurrence за исключением того, что эта итерация представлена в так называемой закрытой форме. Это означает, что n-ый элемент в серии вычисляется непосредственно из начальных величин и самого n. Это подразумевает, что интерфейс, предлагаемый Sequence – диапазон с произвольным доступом, по сравнению с обычной Recurrence, которая предлагает только лидирующую итерацию.
Состояние последовательности сохраняется как Tuple (кортеж), так что оно может быть разнородным.
Примеры:
Нечетные числа, с использованием функции в форме строки:
auto odds = sequence!("a[0] + n * a[1]")(1, 2);
assert(odds.front == 1);
odds.popFront();
assert(odds.front == 3);
odds.popFront();
assert(odds.front == 5);
Примеры:
Треугольные числа, с использованием функции в лямбда-форме:
auto tri = sequence!((a,n) => n*(n+1)/2)();

// Заметим произвольный доступ
assert(tri[0] == 0);
assert(tri[3] == 6);
assert(tri[1] == 1);
assert(tri[4] == 10);
assert(tri[2] == 3);
Примеры:
Числа Фибоначчи, с использованием функции в явной форме:
import std.math : pow, round, sqrt;
static ulong computeFib(S)(S state, size_t n)
{
    // Формула Бине
    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,    // Золотое сечение
    (1.0 - sqrt(5.0)) / 2.0,    // Сопряжение к Золотому сечению
    sqrt(5.0));

// Заметьте произвольный доступ через оператор [] 
assert(fib[1] == 1);
assert(fib[4] == 5);
assert(fib[3] == 3);
assert(fib[2] == 2);
assert(fib[9] == 55);
auto iota(B, E, S)(B begin, E end, S step)
if ((isIntegral!(CommonType!(B, E)) || isPointer!(CommonType!(B, E))) && isIntegral!S);

auto iota(B, E)(B begin, E end)
if (isFloatingPoint!(CommonType!(B, E)));

auto iota(B, E)(B begin, E end)
if (isIntegral!(CommonType!(B, E)) || isPointer!(CommonType!(B, E)));

auto iota(E)(E end)
if (is(typeof(iota(E(0), end))));

auto iota(B, E, S)(B begin, E end, S step)
if (isFloatingPoint!(CommonType!(B, E, S)));

auto iota(B, E)(B begin, E end)
if (!isIntegral!(CommonType!(B, E)) && !isFloatingPoint!(CommonType!(B, E)) && !isPointer!(CommonType!(B, E)) && is(typeof((ref B b) { ++b; } )) && (is(typeof(B.init < E.init)) || is(typeof(B.init == E.init))));
Создаёт диапазон значений, которые находятся между данными начальным и конечным значениями.
Параметры:
B begin Начальное значение.
E end Значение, которое служит в качестве останавливающего критерия. Это значение не включается в диапазон.
S step Значение, добавляемое к текущему значению в каждой итерации.
Возвращает:
Диапазон, который проходит по числам begin, begin + step, begin + 2 * step, ..., вплоть до end (исключая его).
Двух-аргументная перегрузка имеет step = 1. Если begin < end && step < 0 или begin > end && step > 0 или begin == end, тогда возвращается пустой диапазон. Если step == 0, тогда begin == end является ошибкой.
Для встроенных типов, возвращаемый диапазон является диапазоном с произвольным доступом. Для типов, определяемых пользователем, которые поддерживают оператор ++, диапазон является входным диапазоном.

Пример:

void main()
{
    import std.stdio;

    // Все следующие группы выдают одно и то же на выходе:
    // 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][]));
r = iota(0, 11, 3);
assert(equal(r, [0, 3, 6, 9][]));
assert(r[2] == 6);
auto rf = iota(0.0, 0.5, 0.1);
assert(approxEqual(rf, [0.0, 0.1, 0.2, 0.3, 0.4]));

Переместиться к: assumeJagged · assumeNotJagged · enforceNotJagged

enum TransverseOptions: int;
Опция для диапазонов FrontTransversal и Transversal (ниже).
assumeJagged
При выполнении transversal (поперечный), допускается, что элементы диапазона диапазонов имеют различные длины (например, jagged array).
enforceNotJagged
transversal обеспечивает соблюдение того, что элементы диапазона диапазонов имеют одинаковую длину (например, массив массивов, все имеют одинаковую длину). Проверка производится один раз при строительстве поперечного диапазона.
assumeNotJagged
transversal принимает, без проверки, что элементы диапазона диапазонов имеют одинаковую длину. Этот выбор полезен, если проверка уже была сделана снаружи диапазона.

Переместиться к: back · empty · front · length · moveAt · moveBack · moveFront · opDollar · opIndex · opIndexAssign · opSlice · popBack · popFront · save · this

struct FrontTransversal(Ror, TransverseOptions opt = TransverseOptions.assumeJagged);

FrontTransversal!(RangeOfRanges, opt) frontTransversal(TransverseOptions opt = TransverseOptions.assumeJagged, RangeOfRanges)(RangeOfRanges rr);
Дан диапазон диапазонов, итерируется поперёк через первые элементы каждого из вложенных диапазонов.
Примеры:
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 ][]));
this(RangeOfRanges input);
Строится из input.
enum bool empty;

@property ref auto front();

ElementType moveFront();

void popFront();
Примитивы лидирующего диапазона.
@property FrontTransversal save();
Дублирует этот frontTransversal. Заметьте, что будет продублирован только инкапсулированный диапазон дипазонов. Лежащие в основе диапазоны дублироваться не будут.
@property ref auto back();

void popBack();

ElementType moveBack();
Примитивы двунаправленного диапазона. Они предоставляются, если выполняется isBidirectionalRange!RangeOfRanges.
ref auto opIndex(size_t n);

ElementType moveAt(size_t n);

void opIndexAssign(ElementType val, size_t n);

@property size_t length();

alias opDollar = length;
Примитивы диапазона с произвольным доступом. Они предоставляются, если выполняется isRandomAccessRange!RangeOfRanges && (opt == TransverseOptions.assumeNotJagged || opt == TransverseOptions.enforceNotJagged).
typeof(this) opSlice(size_t lower, size_t upper);
Поддержка срезов предлагается, если RangeOfRanges поддерживает срезы, и выполняются все условия, необходимые для поддержки индексации.

Переместиться к: back · empty · front · length · moveAt · moveBack · moveFront · opDollar · opIndex · opIndexAssign · opSlice · popBack · popFront · save · this

struct Transversal(Ror, TransverseOptions opt = TransverseOptions.assumeJagged);

Transversal!(RangeOfRanges, opt) transversal(TransverseOptions opt = TransverseOptions.assumeJagged, RangeOfRanges)(RangeOfRanges rr, size_t n);
Дан диапазон диапазонов, итерируется поперёк через n-ый элемент каждого из вложенных диапазонов.
Параметры:
opt Контролирует предположения, которые функция делает о длинах диапазонов
RangeOfRanges rr Входной диапазон диапазонов с произвольным доступом
Возвращает:
Как минимум, входной диапазон. Примитивы таких диапазонов, как например, двунаправленный и с произвольным доступом, предоставляются, если тип элементов rr их предоставляет.
Примеры:
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 ][]));
this(RangeOfRanges input, size_t n);
Строится из input и индекса.
enum bool empty;

Переместиться к: 2

@property ref auto front();

E moveFront();

@property auto front(E val);

void popFront();

@property typeof(this) save();
Примитивы лидирующего диапазона.

Переместиться к: 2

@property ref auto back();

void popBack();

E moveBack();

@property auto back(E val);
Примитивы двунаправленного диапазона. Они предоставляются, если выполняется isBidirectionalRange!RangeOfRanges.
ref auto opIndex(size_t n);

E moveAt(size_t n);

void opIndexAssign(E val, size_t n);

@property size_t length();

alias opDollar = length;
Примитивы диапазона с произвольным доступом. Они предоставляются, если выполняется isRandomAccessRange!RangeOfRanges && (opt == TransverseOptions.assumeNotJagged || opt == TransverseOptions.enforceNotJagged).
typeof(this) opSlice(size_t lower, size_t upper);
Поддержка срезов предлагается, если RangeOfRanges поддерживает срезы, и выполняются все условия, необходимые для поддержки индексации.
Transposed!RangeOfRanges transposed(RangeOfRanges)(RangeOfRanges rr)
if (isForwardRange!RangeOfRanges && isInputRange!(ElementType!RangeOfRanges) && hasAssignableElements!RangeOfRanges);
Дан диапазон диапазонов, возвращается диапазон диапазонов, где i-й поддиапазон содержит i-е элементы исходных поддиапазонов.
Примеры:
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)
{
    assert(array(e) == witness[i++]);
}

Переместиться к: back · front · indices · length · moveAt · moveBack · moveFront · opIndex · opIndexAssign · opSlice · physicalIndex · popBack · popFront · save · source

struct Indexed(Source, Indices) if (isRandomAccessRange!Source && isInputRange!Indices && is(typeof(Source.init[ElementType!Indices.init])));

Indexed!(Source, Indices) indexed(Source, Indices)(Source source, Indices indices);
Эта структура принимает два диапазона, source (источник) и indices(индексы), и создаёт видимость источника, как будто его элементы были переупорядочены в соответсвии с indices. Индексы могут включать только подмножество элементов источника, и могут также повторять элементы.
Source должен быть диапазоном с произвольным доступом. Возвращаемый диапазон будет двунаправленным или с произвольным доступом, если Indices является двунаправленным или с произвольным доступом, соответственно.
Примеры:
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]));

Переместиться к: 2

@property ref auto front();

void popFront();

@property typeof(this) save();

@property ref auto front(ElementType!Source newVal);

auto moveFront();

Переместиться к: 2

@property ref auto back();

void popBack();

@property ref auto back(ElementType!Source newVal);

auto moveBack();

@property size_t length();

ref auto opIndex(size_t index);

typeof(this) opSlice(size_t a, size_t b);

auto opIndexAssign(ElementType!Source newVal, size_t index);

auto moveAt(size_t index);
Примитивы диапазона
@property Source source();
Возвращает диапазон source.
@property Indices indices();
Возвращает диапазон indices.
size_t physicalIndex(size_t logicalIndex);
Возвращает физический индекс в исходном диапазоне, соответствующий данному логическому индексу. Это полезно, например, при индексировании Indexed без добавления ещё одного слоя косвенности.
Примеры:
auto ind = indexed([1, 2, 3, 4, 5], [1, 3, 4]);
assert(ind.physicalIndex(0) == 1);

Переместиться к: back · empty · front · length · opIndex · opSlice · popBack · popFront · save · this

struct Chunks(Source) if (isForwardRange!Source);

Chunks!Source chunks(Source)(Source source, size_t chunkSize)
if (isForwardRange!Source);
Этот диапазон итерирует над кусками фиксированного размера chunkSize исходного диапазона source. Исходный диапазон должен быть лидируюшим диапазоном. chunkSize должен быть больше нуля.
Если !isInfinite!Source и source.walkLength не ровно делится на chunkSize, последний элемент этого диапазона будет содержать меньше элементов, чем chunkSize.
Примеры:
import std.algorithm.comparison : equal;
auto source = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
auto chunks = chunks(source, 4);
assert(chunks[0] == [1, 2, 3, 4]);
assert(chunks[1] == [5, 6, 7, 8]);
assert(chunks[2] == [9, 10]);
assert(chunks.back == chunks[2]);
assert(chunks.front == chunks[0]);
assert(chunks.length == 3);
assert(equal(retro(array(chunks)), array(retro(chunks))));
this(Source source, size_t chunkSize);
Стандартный конструктор
@property auto front();

void popFront();

@property bool empty();

@property typeof(this) save();
Примитивы лидирующего диапазона. Всегда в наличии.
@property size_t length();
Длина. Только если hasLength!Source истинно.
auto opIndex(size_t index);

typeof(this) opSlice(size_t lower, size_t upper);
Операции индексации и получения среза. Предоставляются только, если hasSlicing!Source истинно.
@property auto back();

void popBack();
Примитивы двунаправленного диапазона. Они предоставляются, если одновременно hasSlicing!Source и hasLength!Source истинны.

Переместиться к: back · empty · front · length · opIndex · opSlice · popBack · popFront · save · this

struct EvenChunks(Source) if (isForwardRange!Source && hasLength!Source);

EvenChunks!Source evenChunks(Source)(Source source, size_t chunkCount)
if (isForwardRange!Source && hasLength!Source);
Этот диапазон разделяет исходный диапазон source на chunkCount кусков приблизительно равной длины. Источник должен быть лидирующим диапазоном с известной длиной.
В отличие от chunks, evenChunks принимает количество кусков (не размер). Возвращаемый диапазон будет содержать нуль или более source.length / chunkCount + 1 элементов с последующими source.length / chunkCount элементов. Если source.length < chunkCount, некоторые куски будут пустыми.
chunkCount не должен быть нулем, если source также не является пустым.
Примеры:
import std.algorithm.comparison : equal;
auto source = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
auto chunks = evenChunks(source, 3);
assert(chunks[0] == [1, 2, 3, 4]);
assert(chunks[1] == [5, 6, 7]);
assert(chunks[2] == [8, 9, 10]);
this(Source source, size_t chunkCount);
Стандарный конструктор
@property auto front();

void popFront();

@property bool empty();

@property typeof(this) save();
Примитивы лидирующего диапазона. Всегда в наличии.
const @property size_t length();
Длина
auto opIndex(size_t index);

typeof(this) opSlice(size_t lower, size_t upper);

@property auto back();

void popBack();
Операции индексирования, получения среза и примитивы двунаправленного диапазона. Предоставляются только, если hasSlicing!Source истинно.
auto only(Values...)(auto ref Values values)
if (!is(CommonType!Values == void) || Values.length == 0);
Собирает значения values в диапазоне, который содержит в себе все свои элементы на месте.
Полезно, когда одиночное значение или несколько отдельных значений нужно передать в алгоритм, ожидающий диапазон, без необходимости выполнять динамическое распределение памяти.
Так как копирование диапазона означает копирование всех элементов, его можно благополучно возвращать из функций. По этой же причине, копирование возвращаемого диапазона может быть дорого для множества аргументов.div>
Примеры:
import std.algorithm.comparison : equal;
import std.algorithm.iteration : filter, joiner, map;
import std.algorithm.searching : findSplitBefore;
import std.uni : isUpper;

assert(equal(only('♡'), "♡"));
assert([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 // взять большие символы
    .map!only       // сделать каждый символ собственным диапазоном
    .joiner(".")    // лениво соединить диапазоны вместе
    .equal("T.D.P.L"));
auto enumerate(Enumerator = size_t, Range)(Range range, Enumerator start = 0)
if (isIntegral!Enumerator && isInputRange!Range);
Итерировать диапазон range с прилагаемой индексной переменной.
Каждый элемент является std.typecons.Tuple, содержащий индекс и элемент, в таком порядке, где индексный член называется index и элемент называется value.
Индекс начинается со start и увеличивается на единицу в каждой итерации.

Переполнение: Если range имеет длину, то будет ошибкой передавать значение для start так, что start + range.length больше, чем Enumerator.max, таким образом обеспечивается, что переполнение не случится.

Если range нет имеет длины, и popFront вызывается, когда front.index == Enumerator.max, индекс переполнится и продолжит с Enumerator.min.

Параметры:
Range range входной диапазон для присоединения индексов
Enumerator start число, с которого начинается счёт индексов
Возвращает:
Как минимум, входной дипазон. Все остальные примитивы диапазона присутствуют в результирующем диапазоне, если они есть у range . За исключением примитивов двунаправленных диапазонов, которые распространяются, только если range имеет длину.

Пример: Полезно для использования foreach с переменной индекса цикла:

    import std.stdio : stdin, stdout;
    import std.range : enumerate;

    foreach (lineNum, line; stdin.byLine().enumerate(1))
        stdout.writefln("line #%s: %s", lineNum, line);

Примеры:
Можно начинать нумерацию с отрицательной позиции:
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]);
enum auto isTwoWayCompatible(alias fn, T1, T2);
Возвращает true, если fn принимает переменные типа T1 и T2 в любом порядке. Следующий код должен компилироваться:
T1 foo();
T2 bar();

fn(foo(), bar());
fn(bar(), foo());

Переместиться к: binarySearch · gallop · gallopBackwards · linear · trot · trotBackwards

enum SearchPolicy: int;
Политика (какого хрена способ поиска называют политикой??? ненавижу политиков!!! – от пер.), используемая примитивами поиска lowerBound, upperBound, и equalRange диапазона SortedRange, показанного ниже.
linear
Поиск линейным способом.
trot
Поиск с шагом, который растет линейно (1, 2, 3,...), что приводит к квадратичному плану поиска (проверяются индексы – 0, 1, 3, 6, 10, 15, 21, 28,...). Как только поиск проскочет свою цель, в оставшемся интервале будет использован двоичный поиск. Поиск завершается за время Ο(sqrt(n)). Используйте его, когда вы достаточно уверены, что искомое значение близко к началу диапазона.
gallop
Выполняет galloping алгоритм поиска, то есть поиск с шагом, который удваивается каждый раз, (1, 2, 4, 8,...), что приводит к экспоненциальному плану поиска (проверяются индексы – 0, 1, 3, 7, 15, 31, 63,...). Как только поиск проскочет свою цель, в оставшемся интервале будет использован двоичный поиск. Значение находится за время Ο(log(n)).
binarySearch
Ищет, используя классический алгоритм, делящий интервал пополам. Поиск начинается в середине диапазона, и каждых шаг поиска делит диапазон пополам. Эта политика находит значение за время Ο(log(n)), но она менее дружественна к кешу, чем gallop в случае больших диапазонов. Политика binarySearch используется как последний шаг в стратегиях trot, gallop, trotBackwards, and gallopBackwards.
trotBackwards
Аналогично trot, но двигается назад. Используйте его, когда уверены, что искомая величина находится близко к концу диапазона.
gallopBackwards
Аналогично gallop, но двигается назад. Используйте его, когда уверены, что искомая величина находится близко к концу диапазона.

Переместиться к: back · contains · empty · equalRange · front · groupBy · length · lowerBound · opDollar · opIndex · opSlice · popBack · popFront · release · save · trisect · upperBound

struct SortedRange(Range, alias pred = "a < b") if (isInputRange!Range);
Представляет отсортированный диапазон. Дополнительно к стандартным примитивам диапазона, поддерживает дополнительные операции, которые используют преимущества упорядочения, такие как слияние и бинарный поиск. Для того, чтобы получить SortedRange из несортированного диапазона r, используйте std.algorithm.sorting.sort , который сортирует r на месте и возвращает соответствующий SortedRange. Для того, чтобы создать SortedRange из диапазона r , про который известно, что он уже отсортирован, используйте assumeSorted , описанное ниже.
Примеры:
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));
assert(r1.release() == [ 64, 52, 42, 3, 2, 1 ]);
Примеры:
SortedRange мог бы принимать диапазоны более слабые, чем с произвольным доступом, но не в состоянии предоставить интересную функциональность для них. Поэтому SortedRange в настоящее время ограничивается диапазонами с произвольным доступом.
Никакой копии оригинального диапазона не создаётся. Если лежащий в основе диапазон изменяется параллельно со своим соответствующим SortedRange способами, которые нарушают его сортированность, SortedRange будет работать с перебоями.
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]);         // незаконное нарушение сортированности исходного диапазона
assert(!r.contains(42));  // проходит, хотя не должно
@property bool empty();

@property auto save();

@property ref auto front();

void popFront();

@property ref auto back();

void popBack();

ref auto opIndex(size_t i);

auto opSlice(size_t a, size_t b);

@property size_t length();

alias opDollar = length;
Примитивы диапазона.
auto release();
Освобождает контролируемый диапазон и возвращает его.
auto lowerBound(SearchPolicy sp = SearchPolicy.binarySearch, V)(V value)
if (isTwoWayCompatible!(predFun, ElementType!Range, V) && hasSlicing!Range);
Эта функция использует поиск с политикой sp для нахождения самого большого левого поддиапазона, для которого pred(x, value) – истина для всех x (например, если pred – это "меньше, чем", возвращает часть диапазона с элементами, которые строго меньше, чем value). План поиска и его сложности описаны в SearchPolicy. Смотрите также lower_bound в STL.
Примеры:
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 ]));
auto upperBound(SearchPolicy sp = SearchPolicy.binarySearch, V)(V value)
if (isTwoWayCompatible!(predFun, ElementType!Range, V));
Эта функция использует поиск с политикой sp для нахождения самого большого правого поддиапазона, для которого pred(value, x) – истина для всех x (например, если pred – это "меньше, чем", возвращает часть диапазона с элементами, которые строго больше, чем value). План поиска и его сложность описаны в SearchPolicy.
Для диапазонов, которые не предлагают произвольный доступ, SearchPolicy.linear – единственная допустимая политика (и это должно быть указано в явном виде, чтобы пользовательский код не оказался неожиданно неэффективым). Для поисков с произвольным доступом допустимы все политики, и по-умолчанию используется SearchPolicy.binarySearch.
Смотрите также:
upper_bound в STL.
Примеры:
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]));
auto equalRange(V)(V value)
if (isTwoWayCompatible!(predFun, ElementType!Range, V) && isRandomAccessRange!Range);
Возвращает поддиапазон, содержащий все элементы e, для которых как pred(e, value), так и pred(value, e) рассчитываются как false (напр, если pred – это "менее, чем", возвращает часть диапазона с элементами равными value). Использует классический двоичный поиск с интервалом, уменьшающимся вдвое, пока не найдет значение, удовлетворяющее условию, затем использует SearchPolicy.gallopBackwards для нахождения левой границы, и SearchPolicy.gallop для нахождения правой границы. Эти политики оправданы тем, что две границы, вероятно, будут рядом с первым обнаруженным значением (то есть, равные области сравнительно небольшие). Весь поиск выполняется за время Ο(log(n)). Смотрите также equal_range в STL.
Примеры:
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 ]));
auto trisect(V)(V value)
if (isTwoWayCompatible!(predFun, ElementType!Range, V) && isRandomAccessRange!Range);
Возвращает такой кортеж r, что r[0] – это то же, что и результат lowerBound(value), r[1] – это то же, что и результат equalRange(value), и r[2] – это то же, что и результат upperBound(value). Вызов быстрее, чем вычисление всех трёх по-отдельности. Использует план поиска, подобный equalRange. Весь поиск завершает за время Ο(log(n)).
Примеры:
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 ]));
bool contains(V)(V value)
if (isRandomAccessRange!Range);
Возвращает true тогда и только тогда, когда value можно найти в диапазоне, который считается отсортированным. Выполняется за Ο(log(r.length)) вычислений pred. Смотрите также binary_search в STL.
auto groupBy()();
Возвращает дипазон поддиапазонов элементов, которые эквивалентны согласно сортирующему соотношению.
auto assumeSorted(alias pred = "a < b", R)(R r)
if (isInputRange!(Unqual!R));
Предполагает, что r отсортирован предикатом pred и возвращает соответствующий SortedRange!(pred, R), использующий r как поддержку. Чтобы удерживать низкий уровень издержек на проверки, стоимость Ο(1) в режиме выпуска (release mode, никаких проверок или сравнений не выполняется). В отладочном режиме (debug mode), несколько произвольных элементов r проверяются на сортированность. Размер образца пропорционален Ο(log(r.length)). Таким образом, проверка не имеет никакого влияния на сложность последующих операций, характерных для отсортированных диапазонов (например, двоичный поиск). Вероятность для произвольного несортированного диапазона провалить тест очень высока (тем не менее, почти-отсортированный диапазон, вероятно, будет передан). Чтобы достоверно проверить, отсортирован ли диапазон, за время Ο(n), используйте std.algorithm.sorting.isSorted.

Переместиться к: back · empty · front · length · moveAt · moveBack · moveFront · opAssign · opDollar · opIndex · opSlice · popBack · popFront · ptr · save · this

struct RefRange(R) if (isInputRange!R);

auto refRange(R)(R* range)
if (isInputRange!R && !is(R == class));

auto refRange(R)(R* range)
if (isInputRange!R && is(R == class));
Обёртка, которая эффективно делает возможным передавать диапазон по ссылке. И исходный диапазон range , и RefRange всегда будут иметь одни и те же элементы. Любое действие, выполненное с одним, влияет на другое.
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 работает в нормальном режиме и работает на новом диапазоне, так что если save когда-либо вызывается на RefRange, то никакие действия в сохранённом диапазоне не повлияют на оригинал.

Параметры:
R* range диапазон, из которого создаётся RefRange
Возвращает:
A RefRange. Если данный диапазон является классическим типом (и, таким образом, уже ссылочный тип), то возвращается исходный диапазон, а не RefRange.
Примеры:
Базовый пример
import std.algorithm.searching : find;
ubyte[] buffer = [1, 9, 45, 12, 22];
auto found1 = find(buffer, 45);
assert(found1 == [45, 12, 22]);
assert(buffer == [1, 9, 45, 12, 22]);

auto wrapped1 = refRange(&buffer);
auto found2 = find(wrapped1, 45);
assert(*found2.ptr == [45, 12, 22]);
assert(buffer == [45, 12, 22]);

auto found3 = find(wrapped1.save, 22);
assert(*found3.ptr == [22]);
assert(buffer == [45, 12, 22]);

string str = "hello world";
auto wrappedStr = refRange(&str);
assert(str.front == 'h');
str.popFrontN(5);
assert(str == " world");
assert(wrappedStr.front == ' ');
assert(*wrappedStr.ptr == " world");
Примеры:
Пример с opAssign.
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;

//Всё указывает туда же, как раньше.
assert(wrapped1.ptr is &buffer1);
assert(wrapped2.ptr is &buffer2);
assert(wrapped1.ptr !is wrapped2.ptr);

//Но buffer1 изменился из-за присваивания.
assert(buffer1 == [6, 7, 8, 9, 10]);
assert(buffer2 == [6, 7, 8, 9, 10]);

buffer2 = [11, 12, 13, 14, 15];

//Всё указывает туда же, как раньше.
assert(wrapped1.ptr is &buffer1);
assert(wrapped2.ptr is &buffer2);
assert(wrapped1.ptr !is wrapped2.ptr);

//Но buffer2 изменился из-за присваивания.
assert(buffer1 == [6, 7, 8, 9, 10]);
assert(buffer2 == [11, 12, 13, 14, 15]);

wrapped2 = null;

//Указатель изменился у wrapped2 но не у wrapped1.
assert(wrapped1.ptr is &buffer1);
assert(wrapped2.ptr is null);
assert(wrapped1.ptr !is wrapped2.ptr);

//buffer2 не зависит от присваивания.
assert(buffer1 == [6, 7, 8, 9, 10]);
assert(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);  // версия диапазона без произвольного доступа

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);
pure nothrow @safe this(R* range);

Переместиться к: 2

auto opAssign(RefRange rhs);
Здесь не присваивается указатель rhs на этот RefRange. Rather it assigns the range pointed to by rhs to the range pointed to by this RefRange. Вместо этого присваивается диапазон, на который указывает rhs на диапазон, на который указывает этот RefRange. Дело в том, что любое действие на RefRange - то же самое, как если бы оно произошло в исходном диапазоне. Единственное исключение - когда RefRange присвоен null или непосредственно, или потому что rhs равно null. В этом случае RefRange больше не относится к исходному диапазону, но равна null.
auto opAssign(typeof(null) rhs);
inout pure nothrow @property @safe inout(R*) ptr();
Указатель на обёрнутый диапазон.
@property auto front();

const @property auto front();

@property auto front(ElementType!R value);
@property bool empty();

const @property bool empty();
void popFront();
@property auto save();

const @property auto save();

Переместиться к: 2

auto opSlice();

const auto opSlice();
Определено, только если isForwardRange!R — истина.
@property auto back();

const @property auto back();

@property auto back(ElementType!R value);

void popBack();
Определено, только если isBidirectionalRange!R — истина.
ref auto opIndex(IndexType)(IndexType index);

const ref auto opIndex(IndexType)(IndexType index);
Определено, только если isRandomAccesRange!R — истина.
auto moveFront();
Определено, только если hasMobileElements!R и isForwardRange!R — истина.
auto moveBack();
Определено, только если hasMobileElements!R и isBidirectionalRange!R — истина.
auto moveAt(size_t index);
Определено, только если hasMobileElements!R и isRandomAccessRange!R — истина.
@property auto length();

const @property auto length();

alias opDollar = length;
Определено, только если hasLength!R — истина.
auto opSlice(IndexType1, IndexType2)(IndexType1 begin, IndexType2 end);

const auto opSlice(IndexType1, IndexType2)(IndexType1 begin, IndexType2 end);
Определено, только если hasSlicing!R — истина.
struct NullSink;
Выходной диапазон (OutputRange), который выбрасывает полученные им данные.
Примеры:
import std.algorithm.iteration : map;
import std.algorithm.mutation : copy;
[4, 5, 6].map!(x => x * 2).copy(NullSink()); // данные удаляются
auto tee(Flag!"pipeOnPop" pipeOnPop = Yes.pipeOnPop, R1, R2)(R1 inputRange, R2 outputRange)
if (isInputRange!R1 && isOutputRange!(R2, ElementType!R1));

auto tee(alias fun, Flag!"pipeOnPop" pipeOnPop = Yes.pipeOnPop, R1)(R1 inputRange)
if (is(typeof(fun) == void) || isSomeFunction!fun);
Реализует "развилку", завёртывая входной диапазон так, чтобы элементы диапазона можно было передать в предусмотренную функцию или в OutputRange во время итерирования над ним. Это полезно для распечатки промежуточных значений в длинной цепи диапазонного кода, выполнения некоторого действия с побочными эффектами при каждом вызове front или popFront, или отклонения элементов диапазона на вспомогательный OutputRange.
Важно заметить, что, так как результирующий диапазон вычисляется лениво, в случае версии tee , которая принимает функцию, функция на самом деле не будет выполнена, пока диапазон "не пройдет", используя функции, вычисляющие диапазоны, как например, std.array.array или std.algorithm.iteration.fold.
Параметры:
pipeOnPop Если Yes.pipeOnPop, просто итерирует диапазон, никогда не вызывая front этого достаточно, чтобы получить на развилке зеркальные элементы на outputRange (или, соответственно, fun). Если No.pipeOnPop, только элементы, для которых front действительно вызван, также будут посланы в outputRange/fun.
R1 inputRange Входной диапазон, проходящий через.
R2 outputRange Этот диапазон будет получать элементы inputRange постепенно, по мере продолжения итерации.
fun Эта функция будет вызвана с элементами inputRange постепенно, по мере продолжения итерации.
Возвращает:
Входной диапазон, который предлагает элементы inputRange. Независимо от того, что inputRange может быть более мощным диапазоном (лидирующим, двунаправленным и т.п.), результат всегда является входным диапазоном. Их чтение вызывает итерирование inputRange и возвращение его элементов в свою очередь. Кроме того, те же элементы будут также переданы в outputRange или fun.
Смотрите также:
Примеры:
import std.algorithm.comparison : equal;
import std.algorithm.iteration : filter, map;

// Суммирует значения при копировании
int[] values = [1, 4, 9, 16, 25];
int sum = 0;
auto newValues = values.tee!(a => sum += a).array;
assert(equal(newValues, values));
assert(sum == 1 + 4 + 9 + 16 + 25);

// Считает значения, которые прошли первый фильтр
int count = 0;
auto newValues4 = values.filter!(a => a < 10)
                        .tee!(a => count++)
                        .map!(a => a + 1)
                        .filter!(a => a < 10);

//equal рассчитывает любые ленивые диапазоны, переданные ему. 
//count не равен 3, пока equal не вычислит newValues4
assert(equal(newValues4, [2, 5]));
assert(count == 3);
auto padLeft(R, E)(R r, E e, size_t n)
if ((isInputRange!R && hasLength!R || isForwardRange!R) && !is(CommonType!(ElementType!R, E) == void));
Увеличивает длину входного диапазона r , заполняя начало диапазона элементом e. Элемент e должен быть общего типа с типом элементов диапазона r , как определено std.traits.CommonType. Если n меньше, чем длина r, тогда r возвращается немодифицированным.
Если r — это строка с символами Юникода, padLeft следует правилам D о длине для строк, в которых считается количество не символов, или графем, но вместо этого количество encoding units. Если вы хотите рассматривать каждую графему как один encoding unit, тогда вызовите std.uni.byGrapheme перед вызовом этой функции.
Если r имеет свойство length (длина), тогда это — Ο(1). В противном случае, это — Ο(r.length).
Параметры:
R r входной диапазон с длиной, или лидирующий диапазон
E e элемент, который должен заполнить диапазон
size_t n длина, до которой заполнить
Возвращает:
Диапазон, содержащий элементы исходного диапазона с дополнительным заполнением
Смотрите также: 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"));
auto padRight(R, E)(R r, E e, size_t n)
if (isInputRange!R && !isInfinite!R && !is(CommonType!(ElementType!R, E) == void));
Увеличивает длину входного диапазона r , заполняя конец диапазона элементом e. Элемент e должен быть общего типа с типом элементов диапазона r , как определено std.traits.CommonType. Если n меньше, чем длина r, тогда r возвращается немодифицированным.
Примитивы диапазона, которые результирующий диапазон предоставляет, зависят от того, предоставляет ли их r. Исключением являются функции back и popBack, которые также требуют, чтобы диапазон имел длину вдобавок к back и popBack.
Параметры:
R r входной диапазон с длиной
E e элемент, который должен заполнить диапазон
size_t n длина, до которой заполнить
Возвращает:
Диапазон, содержащий элементы исходного диапазона с дополнительным заполнением
Смотрите также: 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___"));