std.range
В этом модуле определено понятие диапазона. Диапазоны обобщают понятие массивов, списков или чего угодно, что предполагает последовательный доступ. Эта абстракция позволяет использовать один и тот же набор алгоритмов (см. std.algorithm) с огромным разнообразием различных конкретных типов. Например, алгоритм линейного поиска, такой как std.algorithm.searching.find, работает не только для массивов, но и для связанных списков, входных файлов, входящих сетевых данных и т. д.
- Руководства
- Существует множество статей, которые помогут лучше понять диапазоны:
- Учебник Али Чеhreli's по диапазонам для основ работы с диапазонами и создания кода, ориентированного на них.
- Выступление Джонатана М. Дэвиса Вступление к диапазонам на DConf 2015 — яркое введение от основных понятий до практических советов.
- Глава учебника DLang Tour по диапазонам для интерактивного знакомства.
- Учебник H. S. Teoh по компонентному программированию с использованием диапазонов для демонстрации реального применения влияния программирования с использованием диапазонов на сложные алгоритмы.
- Статья Андреа Александреску Об итерации для концептуального понимания диапазонов и мотивации
- Подмодули
- Этот модуль содержит два подмодуля:
std.range.primitives предоставляет базовые функциональные возможности для работы с диапазонами. Он определяет несколько шаблонов для проверки того, является ли данный объект диапазоном, какой это диапазон, и предоставляет некоторые общие операции с диапазонами. Подмодуль std.range.interfaces предоставляет интерфейсы на основе объектов для работы с диапазонами с помощью полиморфизма во время выполнения. Остальная часть модуля предоставляет богатый набор шаблонов для создания и композиции диапазонов, позволяющих создавать новые диапазоны из существующих: chain | Объединяет несколько диапазонов в один диапазон. |
choose | Выбирает один из двух диапазонов во время выполнения на основе булевого условия. |
chooseAmong | Выбирает один из нескольких диапазонов во время выполнения на основе индекса. |
chunks | Создает диапазон, возвращающий куски заданного размера из исходного диапазона. |
cycle | Создает бесконечный диапазон, повторяющий заданный диапазон вперед бесконечно. Подходит для реализации циклических буферов. |
drop | Создает диапазон, полученный из заданного диапазона путём отбрасывания первых n элементов. |
dropBack | Создает диапазон, полученный из заданного диапазона путём отбрасывания последних n элементов. |
dropExactly | Создает диапазон, полученный из заданного диапазона путём отбрасывания ровно n первых элементов. |
dropBackExactly | Создает диапазон, полученный из заданного диапазона путём отбрасывания ровно n последних элементов. |
dropOne | Создает диапазон, полученный из заданного диапазона путём отбрасывания первого элемента. |
dropBackOne | Создает диапазон, полученный из заданного диапазона путём отбрасывания последнего элемента. |
enumerate | Итерирует диапазон с присоединённой переменной индекса. |
evenChunks | Создаёт диапазон, возвращающий куски примерно равной длины из исходного диапазона. |
frontTransversal | Создаёт диапазон, итерирующий по первым элементам заданных диапазонов. |
generate | Создаёт диапазон последовательными вызовами заданной функции. Это позволяет создавать диапазоны как единый делегат. |
indexed | Создаёт диапазон, представляющий заданный диапазон так, как будто его элементы были переупорядочены в соответствии с заданным диапазоном индексов. |
iota | Создаёт диапазон, состоящий из чисел между начальной и конечной точкой, с заданным интервалом. |
lockstep | Итерирует n диапазонов синхронно, для использования в цикле foreach. Похоже на zip, за исключением того, что lockstep предназначен специально для циклов foreach. |
nullSink | Диапазон вывода, который отбрасывает получаемые данные. |
only | Создаёт диапазон, итерирующий по заданным аргументам. |
padLeft | Заполняет диапазон до заданной длины, добавляя заданный элемент в начало диапазона. Ленивый, если длина диапазона известна. |
padRight | Лениво заполняет диапазон до заданной длины, добавляя заданный элемент в конец диапазона. |
radial | Принимая диапазон с произвольным доступом и начальную точку, создаёт диапазон, который поочерёдно возвращает следующий левый и следующий правый элемент относительно начальной точки. |
recurrence | Создаёт диапазон вперед, значения которого определяются рекуррентным соотношением. |
refRange | Передаёт диапазон по ссылке. И исходный диапазон, и RefRange всегда будут содержать точно такие же элементы. Любая операция, выполненная с одним из них, повлияет на другой. |
repeat | Создаёт диапазон, состоящий из одного элемента, повторяющегося n раз, или бесконечный диапазон, бесконечно повторяющий этот элемент. |
retro | Итерирует двунаправленный диапазон в обратном порядке. |
roundRobin | Принимая n диапазонов, создаёт новый диапазон, возвращающий по очереди первые n элементов каждого диапазона, затем второй элемент каждого диапазона и так далее по кругу. |
sequence | Аналогично recurrence, за исключением того, что создаётся диапазон с произвольным доступом. |
slide | Создаёт диапазон, возвращающий слайдинг-окно фиксированного размера над исходным диапазоном. В отличие от кусков, он перемещается на определённое количество элементов за раз, а не на один кусок за раз. |
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 1.0.
- Авторы:
- Андрей Александреску, Дэвид Симча, Джонатан М. Дэвис и Джек Стауффер. Часть идей для создания этого модуля принадлежит Леонардо Маффи.
- auto retro(Range)(Range r)
Constraints: if (isBidirectionalRange!(Unqual!Range)); -
Итерирует двунаправленный диапазон в обратном порядке. Исходный диапазон можно получить, используя свойство
source. Применение retro дважды к одному и тому же диапазону возвращает исходный диапазон.- Параметры:
Range rдвунаправленный диапазон для итерации в обратном порядке
- Возвращает:
- Двунаправленный диапазон с длиной, если
rтакже предоставляет длину. В противном случае, еслиrявляется диапазоном произвольного доступа, возвращаемое значение также будет диапазоном произвольного доступа.
- См. также:
-
std.algorithm.mutation.reverseдля изменения исходного диапазона напрямую.
- Примеры:
-
import std.algorithm.comparison : equal; int[5] a = [ 1, 2, 3, 4, 5 ]; int[5] b = [ 5, 4, 3, 2, 1 ]; assert(equal(retro(a[]), b[])); assert(retro(a[]).source is a[]); assert(retro(retro(a[])) is a[]);
- auto stride(Range)(Range r, size_t n)
Constraints: if (isInputRange!(Unqual!Range)); -
Итерирует диапазон
rс шагомn. Если диапазон является диапазоном произвольного доступа, перемещение происходит путем индексирования в диапазон; в противном случае, перемещение происходит последовательными вызовамиpopFront. Применение stride дважды к одному и тому же диапазону приводит к шагу, являющемуся произведением двух применений. Ошибка возникает, еслиnравно 0.- Параметры:
Range rвходной диапазон для итерирования с шагом size_t nколичество элементов, которые нужно пропустить
- Возвращает:
- По крайней мере, входной диапазон. Результирующий диапазон примет диапазонные примитивы базового диапазона, при условии, что
std.range.primitives.hasLengthравноtrue.
- Примеры:
-
import std.algorithm.comparison : equal; int[] a = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 ]; assert(equal(stride(a, 3), [ 1, 4, 7, 10 ][])); writeln(stride(stride(a, 2), 3)); // stride(a, 6)
- auto chain(Ranges...)(Ranges rs)
Constraints: 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предоставляют диапазонный примитив, возвращаемый диапазон также будет поддерживать этот примитив.
- См. также:
-
onlyдля объединения значений с диапазоном
- Примеры:
-
import std.algorithm.comparison : equal; int[] arr1 = [ 1, 2, 3, 4 ]; int[] arr2 = [ 5, 6 ]; int[] arr3 = [ 7 ]; auto s = chain(arr1, arr2, arr3); writeln(s.length); // 7 writeln(s[5]); // 6 assert(equal(s, [1, 2, 3, 4, 5, 6, 7][]));
- Примеры:
- Диапазонные примитивы переносятся в возвращаемый диапазон, если все диапазоны их предоставляют
import std.algorithm.comparison : equal; import std.algorithm.sorting : sort; int[] arr1 = [5, 2, 8]; int[] arr2 = [3, 7, 9]; int[] arr3 = [1, 4, 6]; // in-place sorting across all of the arrays auto s = arr1.chain(arr2, arr3).sort; assert(s.equal([1, 2, 3, 4, 5, 6, 7, 8, 9])); assert(arr1.equal([1, 2, 3])); assert(arr2.equal([4, 5, 6])); assert(arr3.equal([7, 8, 9]));
- Примеры:
- Из-за безопасного повышения типа в D, объединение различных символьных диапазонов приводит к диапазону типа
uint. Используйте byChar, byWchar и byDchar для диапазонов, чтобы получить необходимый тип.import std.utf : byChar, byCodeUnit; auto s1 = "string one"; auto s2 = "string two"; // s1 and s2 front is dchar because of auto-decoding static assert(is(typeof(s1.front) == dchar) && is(typeof(s2.front) == dchar)); auto r1 = s1.chain(s2); // chains of ranges of the same character type give that same type static assert(is(typeof(r1.front) == dchar)); auto s3 = "string three".byCodeUnit; static assert(is(typeof(s3.front) == immutable char)); auto r2 = s1.chain(s3); // chaining ranges of mixed character types gives `dchar` static assert(is(typeof(r2.front) == dchar)); // use byChar on character ranges to correctly convert them to UTF-8 auto r3 = s1.byChar.chain(s3); static assert(is(typeof(r3.front) == immutable char));
- auto choose(R1, R2)(bool condition, return scope R1 r1, return scope R2 r2)
Constraints: if (isInputRange!(Unqual!R1) && isInputRange!(Unqual!R2) && !is(CommonType!(ElementType!(Unqual!R1), ElementType!(Unqual!R2)) == void)); -
Выбирает один из двух диапазонов во время выполнения в зависимости от булевого условия.
Диапазоны могут быть различными, но должны иметь совместимые типы элементов (т.е.
CommonTypeдолжен существовать для двух типов элементов). Результатом является диапазон, который поддерживает наименьшие возможности из двух (например,ForwardRangeеслиR1— диапазон произвольного доступа, аR2— диапазон прямого доступа).- Параметры:
bool conditionкоторый диапазон выбрать: r1еслиtrue,r2в противном случаеR1 r1диапазон «истина» R2 r2диапазон «ложь»
- Возвращает:
- Тип диапазона, зависящий от
R1иR2.
- Примеры:
-
import std.algorithm.comparison : equal; import std.algorithm.iteration : filter, map; auto data1 = only(1, 2, 3, 4).filter!(a => a != 3); auto data2 = only(5, 6, 7, 8).map!(a => a + 1); // choose() is primarily useful when you need to select one of two ranges // with different types at runtime. static assert(!is(typeof(data1) == typeof(data2))); auto chooseRange(bool pickFirst) { // The returned range is a common wrapper type that can be used for // returning or storing either range without running into a type error. return choose(pickFirst, data1, data2); // Simply returning the chosen range without using choose() does not // work, because map() and filter() return different types. //return pickFirst ? data1 : data2; // does not compile } auto result = chooseRange(true); assert(result.equal(only(1, 2, 4))); result = chooseRange(false); assert(result.equal(only(6, 7, 8, 9)));
- auto chooseAmong(Ranges...)(size_t index, return scope Ranges rs)
Constraints: if (Ranges.length >= 2 && allSatisfy!(isInputRange, staticMap!(Unqual, Ranges)) && !is(CommonType!(staticMap!(ElementType, Ranges)) == void)); -
Выбирает один из нескольких диапазонов во время выполнения.
Диапазоны могут быть различными, но должны иметь совместимые типы элементов. Результатом является диапазон, который поддерживает наименьшие возможности из всех
Ranges.- Параметры:
size_t indexкоторый диапазон выбрать, должно быть меньше количества диапазонов Ranges rsдва или более диапазонов
- Возвращает:
- Индексированный диапазон. Если rs состоит только из одного диапазона, возвращаемый тип — алиас типа этого диапазона.
- Примеры:
-
auto test() { import std.algorithm.comparison : equal; int[4] sarr1 = [1, 2, 3, 4]; int[2] sarr2 = [5, 6]; int[1] sarr3 = [7]; auto arr1 = sarr1[]; auto arr2 = sarr2[]; auto arr3 = sarr3[]; { auto s = chooseAmong(0, arr1, arr2, arr3); auto t = s.save; writeln(s.length); // 4 writeln(s[2]); // 3 s.popFront(); assert(equal(t, only(1, 2, 3, 4))); } { auto s = chooseAmong(1, arr1, arr2, arr3); writeln(s.length); // 2 s.front = 8; assert(equal(s, only(8, 6))); } { auto s = chooseAmong(1, arr1, arr2, arr3); writeln(s.length); // 2 s[1] = 9; assert(equal(s, only(8, 9))); } { auto s = chooseAmong(1, arr2, arr1, arr3)[1 .. 3]; writeln(s.length); // 2 assert(equal(s, only(2, 3))); } { auto s = chooseAmong(0, arr1, arr2, arr3); writeln(s.length); // 4 writeln(s.back); // 4 s.popBack(); s.back = 5; assert(equal(s, only(1, 2, 5))); s.back = 3; assert(equal(s, only(1, 2, 3))); } { uint[5] foo = [1, 2, 3, 4, 5]; uint[5] bar = [6, 7, 8, 9, 10]; auto c = chooseAmong(1, foo[], bar[]); writeln(c[3]); // 9 c[3] = 42; writeln(c[3]); // 42 writeln(c.moveFront()); // 6 writeln(c.moveBack()); // 10 writeln(c.moveAt(4)); // 10 } { import std.range : cycle; auto s = chooseAmong(0, cycle(arr2), cycle(arr3)); assert(isInfinite!(typeof(s))); assert(!s.empty); writeln(s[100]); // 8 writeln(s[101]); // 9 assert(s[0 .. 3].equal(only(8, 9, 8))); } return 0; } // works at runtime auto a = test(); // and at compile time static b = test();
- auto roundRobin(Rs...)(Rs rs)
Constraints: 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)
Constraints: if (isRandomAccessRange!(Unqual!Range) && hasLength!(Unqual!Range) && hasSlicing!(Unqual!Range) && isIntegral!I);
auto radial(R)(R r)
Constraints: if (isRandomAccessRange!(Unqual!R) && hasLength!(Unqual!R) && hasSlicing!(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 ])); // If the left end is reached first, the remaining elements on the right // are concatenated in order: a = [ 0, 1, 2, 3, 4, 5 ]; assert(equal(radial(a, 1), [ 1, 2, 0, 3, 4, 5 ])); // If the right end is reached first, the remaining elements on the left // are concatenated in reverse order: assert(equal(radial(a, 4), [ 4, 5, 3, 2, 1, 0 ]));
- Take!R take(R)(R input, size_t n)
Constraints: if (isInputRange!(Unqual!R));
struct Take(Range) if (isInputRange!(Unqual!Range) && !(!isInfinite!(Unqual!Range) && hasSlicing!(Unqual!Range) || is(Range T == Take!T)));
template Take(R) if (isInputRange!(Unqual!R) && (!isInfinite!(Unqual!R) && hasSlicing!(Unqual!Range) || is(R T == Take!T))) -
Лениво берет только до
nэлементов диапазона. Это особенно полезно при работе с бесконечными диапазонами.В отличие от
takeExactly,takeне требует, чтобы вnбылоinputили больше элементов. Вследствие этого, информация о длине не применяется к результату, еслиinputтакже не содержит информацию о длине.- Параметры:
R inputвходной диапазон для итерации не более nразsize_t nколичество элементов для взятия
- Возвращает:
- По крайней мере, входной диапазон. Если диапазон поддерживает произвольный доступ и
length,takeтакже поддерживает их.
- Примеры:
-
import std.algorithm.comparison : equal; int[] arr1 = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ]; auto s = take(arr1, 5); writeln(s.length); // 5 writeln(s[4]); // 5 assert(equal(s, [ 1, 2, 3, 4, 5 ][]));
- Примеры:
- Если диапазон исчерпывается до
nэлементов,takeпросто возвращает весь диапазон (в отличие отtakeExactly, который вызовет ошибку утверждения, если диапазон закончится преждевременно):import std.algorithm.comparison : equal; int[] arr2 = [ 1, 2, 3 ]; auto t = take(arr2, 5); writeln(t.length); // 3 assert(equal(t, [ 1, 2, 3 ]));
- auto takeExactly(R)(R range, size_t n)
Constraints: if (isInputRange!R); -
Аналогично
take, но предполагает, чтоrangeимеет по меньшей мереnэлементов. Соответственно, результатtakeExactly(range, n)всегда определяет свойствоlength(и инициализирует его значениемn) даже в случаях, когдаrangeсам не определяетlength.Результат
takeExactlyидентичен результатуtakeв случаях, когда исходный диапазон определяетlengthили является бесконечным.
В отличие от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)); writeln(b.length); // 3 writeln(b.front); // 1 writeln(b.back); // 3
- auto takeOne(R)(R source)
Constraints: if (isInputRange!R); -
Возвращает диапазон с не более чем одним элементом; например,
takeOne([42, 43, 44])возвращает диапазон, состоящий из целого числа42. ВызовpopFront()для этого диапазона делает его пустым.По сути,
takeOne(r)несколько эквивалентенtake(r, 1), но в определенных интерфейсах важно статически знать, что диапазон может содержать не более одного элемента.
Тип, возвращаемыйtakeOne, — это диапазон с произвольным доступом и длиной независимо от возможностейR, если это диапазон с однонаправленным доступом. (ещё одна особенность, отличающаяtakeOneотtake). Если (D R) — это диапазон с однонаправленным доступом, но не диапазон с однонаправленным доступом, тип возвращаемого значения — диапазон с однонаправленным доступом со всеми возможностями произвольного доступа, за исключением сохранения.- Примеры:
-
auto s = takeOne([42, 43, 44]); static assert(isRandomAccessRange!(typeof(s))); writeln(s.length); // 1 assert(!s.empty); writeln(s.front); // 42 s.front = 43; writeln(s.front); // 43 writeln(s.back); // 43 writeln(s[0]); // 43 s.popFront(); writeln(s.length); // 0 assert(s.empty);
- auto takeNone(R)()
Constraints: if (isInputRange!R); -
Возвращает пустой диапазон, который статически известен как пустой и гарантированно будет иметь
lengthи будет иметь произвольный доступ независимо от возможностейR.- Примеры:
-
auto range = takeNone!(int[])(); writeln(range.length); // 0 assert(range.empty);
- auto takeNone(R)(R range)
Constraints: 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)
Constraints: if (isInputRange!Range && !isInfinite!Range && (hasLength!Range || isForwardRange!Range)); -
Возвращает диапазон, смещённый на
_nэлементов от концаrange.Предназначен в качестве диапазонного эквивалента утилиты Unix tail. Когда длина
rangeменьше или равна_n,rangeвозвращается как есть.
Завершается за Ο(1) шагов для диапазонов, которые поддерживают нарезку и имеют длину. Завершается за Ο(range.length) времени для всех остальных диапазонов.- Параметры:
Range rangeдиапазон, из которого необходимо получить хвост size_t nмаксимальное количество элементов, включаемых в хвост
- Возвращает:
- Возвращает хвост
range, дополненный информацией о длине.
- Примеры:
-
// tail -c n writeln([1, 2, 3].tail(1)); // [3] writeln([1, 2, 3].tail(2)); // [2, 3] writeln([1, 2, 3].tail(3)); // [1, 2, 3] writeln([1, 2, 3].tail(4)); // [1, 2, 3] writeln([1, 2, 3].tail(0).length); // 0 // tail --lines=n import std.algorithm.comparison : equal; import std.algorithm.iteration : joiner; import std.exception : assumeWontThrow; import std.string : lineSplitter; assert("one\ntwo\nthree" .lineSplitter .tail(2) .joiner("\n") .equal("two\nthree") .assumeWontThrow);
- R drop(R)(R range, size_t n)
Constraints: if (isInputRange!R);
R dropBack(R)(R range, size_t n)
Constraints: if (isBidirectionalRange!R); -
Функция-обёртка, которая вызывает
std.range.primitives.popFrontN(range, n)и возвращаетrange.dropупрощает извлечение элементов из диапазона и последующую передачу его в другую функцию в одном выражении, в то время какpopFrontNпотребовало бы нескольких инструкций.dropBackобеспечивает ту же функциональность, но вместо этого вызываетstd.range.primitives.popBackN(range, n).- Примечание
-
dropиdropBackизвлекут не болееnэлементов, но остановятся, если диапазон окажется пустым. В других языках это иногда называютskip.
- Параметры:
R rangeдиапазон с однонаправленным доступом для извлечения элементов size_t nколичество элементов для извлечения
- Возвращает:
-
rangeс исключёнными доnэлементов
- См. также:
-
std.range.primitives.popFront,std.range.primitives.popBackN
- Примеры:
-
import std.algorithm.comparison : equal; writeln([0, 2, 1, 5, 0, 3].drop(3)); // [5, 0, 3] writeln("hello world".drop(6)); // "world" assert("hello world".drop(50).empty); assert("hello world".take(6).drop(3).equal("lo "));
- Примеры:
-
import std.algorithm.comparison : equal; writeln([0, 2, 1, 5, 0, 3].dropBack(3)); // [0, 2, 1] writeln("hello world".dropBack(6)); // "hello" assert("hello world".dropBack(50).empty); assert("hello world".drop(4).dropBack(4).equal("o w"));
- R dropExactly(R)(R range, size_t n)
Constraints: if (isInputRange!R);
R dropBackExactly(R)(R range, size_t n)
Constraints: if (isBidirectionalRange!R); -
Аналогично
dropиdropBackно они вызываютrange.popFrontExactly(n)иrange.popBackExactly(n)вместо этого.- Примечание
- В отличие от
drop,dropExactlyпредполагает, что диапазон содержит не менееnэлементов. Это делаетdropExactlyбыстрее, чемdrop, но также означает, что еслиrangeне содержит не менееnэлементов, он попытается вызватьpopFrontна пустом диапазоне, что является неопределённым поведением. Поэтому используйтеpopFrontExactlyтолько в том случае, если гарантируется, чтоrangeсодержит не менееnэлементов.
- Параметры:
R rangeдиапазон с однонаправленным доступом для извлечения элементов size_t nколичество элементов для извлечения
- Возвращает:
-
rangeс удалённымиnэлементами
- См. также:
-
std.range.primitives.popFrontExcatly,std.range.primitives.popBackExcatly
- Примеры:
-
import std.algorithm.comparison : equal; import std.algorithm.iteration : filterBidirectional; auto a = [1, 2, 3]; writeln(a.dropExactly(2)); // [3] writeln(a.dropBackExactly(2)); // [1] string s = "日本語"; writeln(s.dropExactly(2)); // "語" writeln(s.dropBackExactly(2)); // "日" auto bd = filterBidirectional!"true"([1, 2, 3]); assert(bd.dropExactly(2).equal([3])); assert(bd.dropBackExactly(2).equal([1]));
- R dropOne(R)(R range)
Constraints: if (isInputRange!R);
R dropBackOne(R)(R range)
Constraints: 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]; writeln(a.dropOne()); // [2, 3] writeln(a.dropBackOne()); // [1, 2] string s = "日本語"; import std.exception : assumeWontThrow; assert(assumeWontThrow(s.dropOne() == "本語")); assert(assumeWontThrow(s.dropBackOne() == "日本")); auto bd = filterBidirectional!"true"([1, 2, 3]); assert(bd.dropOne().equal([2, 3])); assert(bd.dropBackOne().equal([1, 2]));
- struct Repeat(T);
Repeat!T repeat(T)(T value);
Take!(Repeat!T) repeat(T)(T value, size_t n); -
Создаёт диапазон, повторяющий одно значение.
- Параметры:
T valueзначение для повторения size_t nколичество повторений value
- Возвращает:
- Если
nне определено, бесконечный диапазон с произвольным доступом и нарезкой. Еслиnопределено, диапазон с произвольным доступом и нарезкой.
- Примеры:
-
import std.algorithm.comparison : equal; assert(5.repeat().take(4).equal([5, 5, 5, 5]));
- Примеры:
-
import std.algorithm.comparison : equal; assert(5.repeat(4).equal([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);
auto opSlice(size_t i, size_t j);
enum auto opDollar;
inout auto opSlice(size_t, DollarToken); -
Примитивы диапазонов
- auto generate(Fun)(Fun fun)
Constraints: if (isCallable!fun);
auto generate(alias fun)()
Constraints: if (isCallable!fun); -
Принимая вызываемую (
std.traits.isCallable) функциюfun, создаёт диапазон, чей передний элемент определяется последовательными вызовамиfun(). Это особенно полезно для вызова функций с глобальными побочными эффектами (случайные функции) или для создания диапазонов, представленных как один делегат, а не всей структуройfront/popFront/empty.funможет принимать либо параметр шаблона-алиаса (существующая функция, делегат, тип структуры, определяющейstatic opCall), либо аргумент времени выполнения (делегат, объект-функция). Результирующий диапазон моделирует диапазон с однонаправленным доступом (std.range.primitives.isInputRange). Полученный диапазон вызоветfun()при создании и каждый раз при вызовеpopFront, а кэшированное значение будет возвращено при вызовеfront.- Возвращает:
- диапазон
inputRange, где каждый элемент представляет собой другой вызов функции.
- Примеры:
-
import std.algorithm.comparison : equal; import std.algorithm.iteration : map; int i = 1; auto powersOfTwo = generate!(() => i *= 2)().take(10); assert(equal(powersOfTwo, iota(1, 11).map!"2^^a"()));
- Примеры:
-
import std.algorithm.comparison : equal; //Returns a run-time delegate auto infiniteIota(T)(T low, T high) { T i = high; return (){if (i == high) i = low; return i++;}; } //adapted as a range. assert(equal(generate(infiniteIota(1, 4)).take(10), [1, 2, 3, 1, 2, 3, 1, 2, 3, 1]));
- Примеры:
-
import std.format : format; import std.random : uniform; auto r = generate!(() => uniform(0, 6)).take(10); format("%(%s %)", r);
- struct Cycle(R) if (isForwardRange!R && !isInfinite!R);
template Cycle(R) if (isInfinite!R)
struct Cycle(R) if (isStaticArray!R);
auto cycle(R)(R input)
Constraints: if (isInputRange!R);
Cycle!R cycle(R)(R input, size_t index = 0)
Constraints: if (isRandomAccessRange!R && !isInfinite!R);
@system Cycle!R cycle(R)(ref R input, size_t index = 0)
Constraints: if (isStaticArray!R);
-
Повторяет заданный диапазон в прямом направлении бесконечно. Если исходный диапазон бесконечен (факт, который сделает
Cycleтождественным отображением),Cycleобнаруживает это и меняет своё имя на тип самого диапазона. Это работает и для непрямых диапазонов. Если исходный диапазон имеет произвольный доступ,Cycleпредоставляет произвольный доступ, а также конструктор, принимающий начальную позициюindex.Cycleработает со статическими массивами в дополнение к диапазонам, в основном по причинам производительности.- Примечание
- Входной диапазон не должен быть пустым.
- Совет
- Это отличный способ реализовать простые кольцевые буферы.
- Примеры:
-
import std.algorithm.comparison : equal; import std.range : cycle, take; // Here we create an infinitive cyclic sequence from [1, 2] // (i.e. get here [1, 2, 1, 2, 1, 2 and so on]) then // take 5 elements of this sequence (so we have [1, 2, 1, 2, 1]) // and compare them with the expected values for equality. assert(cycle([1, 2]).take(5).equal([ 1, 2, 1, 2, 1 ]));
- this(R input, size_t index = 0);
@property ref auto front();
const @property ref auto front();
@property void front(ElementType!R val);
enum bool empty;
void popFront();
ref auto opIndex(size_t n);
const ref auto opIndex(size_t n);
void opIndexAssign(ElementType!R val, size_t n);
@property Cycle save();
enum auto opDollar;
auto opSlice(size_t i, size_t j);
auto opSlice(size_t i, DollarToken); -
Примитивы диапазонов
- struct Zip(Ranges...) if (Ranges.length && allSatisfy!(isInputRange, Ranges));
auto zip(Ranges...)(Ranges ranges)
Constraints: if (Ranges.length && allSatisfy!(isInputRange, Ranges));
auto zip(Ranges...)(StoppingPolicy sp, Ranges ranges)
Constraints: if (Ranges.length && allSatisfy!(isInputRange, Ranges)); -
Проход по нескольким диапазонам синхронно. Тип элемента — это прокси-кортеж, позволяющий обращаться к текущему элементу в
n-ом диапазоне, используяe[n].zipаналогиченlockstep, ноlockstepне объединяет свои элементы и использует протоколopApply.lockstepпозволяет получать доступ к элементам по ссылке вforeachитерациях.- Параметры:
StoppingPolicy spуправляет тем, что zipбудет делать, если диапазоны имеют разную длинуRanges rangesдиапазоны для объединения
- Возвращает:
- По меньшей мере, входной диапазон.
Zipпредлагает минимальные возможности диапазонов всех компонентов, например, он предлагает произвольный доступ, если все диапазоны предлагают произвольный доступ, а также предлагает мутацию и обмен, если все диапазоны это предлагают. Благодаря этому,Zipчрезвычайно мощный, потому что он позволяет манипулировать несколькими диапазонами синхронно.
- Исключения:
- Исключение
Exception, если все диапазоны не имеют одинаковую длину, иspустановлено вStoppingPolicy.requireSameLength.
- Ограничения
- Атрибуты
@nogcиnothrowне могут быть определены для структурыZip, потому чтоStoppingPolicyможет изменяться во время выполнения. Это ограничение не распространяется на анонимный диапазон, возвращаемый функциейzip, когда явно не указаноStoppingPolicyв качестве аргумента.
- Примеры:
-
import std.algorithm.comparison : equal; import std.algorithm.iteration : map; // pairwise sum auto arr = only(0, 1, 2); auto part1 = zip(arr, arr.dropOne).map!"a[0] + a[1]"; assert(part1.equal(only(1, 3)));
- Примеры:
-
import std.conv : to; int[] a = [ 1, 2, 3 ]; string[] b = [ "a", "b", "c" ]; string[] result; foreach (tup; zip(a, b)) { result ~= tup[0].to!string ~ tup[1]; } writeln(result); // ["1a", "2b", "3c"] size_t idx = 0; // unpacking tuple elements with foreach foreach (e1, e2; zip(a, b)) { writeln(e1); // a[idx] writeln(e2); // b[idx] ++idx; }
- Примеры:
-
zip— мощный инструмент; следующий код сортирует два массива параллельно:import std.algorithm.sorting : sort; int[] a = [ 1, 2, 3 ]; string[] b = [ "a", "c", "b" ]; zip(a, b).sort!((t1, t2) => t1[0] > t2[0]); writeln(a); // [3, 2, 1] // b is sorted according to a's sorting writeln(b); // ["b", "c", "a"]
- this(R rs, StoppingPolicy s = StoppingPolicy.shortest);
-
Создаёт объект. Обычно вызывается косвенно с помощью функции
zip. - enum bool empty;
-
Возвращает
true, если диапазон достиг конца. Проверка зависит от политики остановки. - @property Zip save();
- @property ElementType front();
-
Возвращает текущий итерируемый элемент.
- @property void front(ElementType v);
-
Устанавливает начало всех итерируемых диапазонов.
- ElementType moveFront();
-
Выталкивает начало.
- @property ElementType back();
-
Возвращает правый крайний элемент.
- ElementType moveBack();
-
Выталкивает конец.
Возвращает правый крайний элемент.
- @property void back(ElementType v);
-
Возвращает текущий итерируемый элемент.
Возвращает правый крайний элемент.
- void popFront();
-
Перемещается к следующему элементу во всех управляемых диапазонах.
- void popBack();
-
Вызывает
popBackдля всех управляемых диапазонов. - @property auto 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-ый элемент в составном диапазоне. Определено, если все диапазоны поддерживают произвольный доступ.
- enum StoppingPolicy: int;
-
Указывает, как должна прекращаться итерация в
zipиlockstep. По умолчанию, остановка происходит по достижению конца самого короткого диапазона.- Примеры:
-
import std.algorithm.comparison : equal; import std.exception : assertThrown; import std.range.primitives; import std.typecons : tuple; auto a = [1, 2, 3]; auto b = [4, 5, 6, 7]; auto shortest = zip(StoppingPolicy.shortest, a, b); assert(shortest.equal([ tuple(1, 4), tuple(2, 5), tuple(3, 6) ])); auto longest = zip(StoppingPolicy.longest, a, b); assert(longest.equal([ tuple(1, 4), tuple(2, 5), tuple(3, 6), tuple(0, 7) ])); auto same = zip(StoppingPolicy.requireSameLength, a, b); same.popFrontN(3); assertThrown!Exception(same.popFront);
- shortest
-
Остановка по достижению конца самого короткого диапазона
- longest
-
Остановка по достижению конца самого длинного диапазона
- requireSameLength
-
Требование, чтобы все диапазоны имели одинаковую длину
- struct Lockstep(Ranges...) if (Ranges.length > 1 && allSatisfy!(isInputRange, Ranges));
Lockstep!Ranges lockstep(Ranges...)(Ranges ranges)
Constraints: if (allSatisfy!(isInputRange, Ranges));
Lockstep!Ranges lockstep(Ranges...)(Ranges ranges, StoppingPolicy s)
Constraints: 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.- Ограничения
- Атрибуты
pure,@safe,@nogc, илиnothrowне могут быть выведены для итерацииlockstep.zipможет вывести первые два из-за другой реализации.
- См. также:
-
ziplockstepаналогичен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; } writeln(arr1); // [7, 9, 11, 13, 15, 100] /// Lockstep also supports iterating with an index variable: foreach (index, a, b; lockstep(arr1, arr2)) { writeln(arr1[index]); // a writeln(arr2[index]); // b }
- 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, функция, вычисляющая следующее значение, указывается как шаблонный аргумент, а начальные значения рекуррентной последовательности передаются как обычные аргументы. Например, в последовательности Фибоначчи есть два начальных значения (и, следовательно, размер состояния 2), потому что для вычисления следующего значения Фибоначчи необходимы два предыдущих значения.
Подпись этой функции должна быть:auto fun(R)(R state, size_t n)
гдеnбудет индексом текущего значения, аstate— непрозрачный вектор состояния, который может быть индексирован с помощью обозначения индекса массиваstate[i], где допустимые значенияiнаходятся в диапазоне от(n - 1)до(n - State.length).
Если функция передаётся в строковой форме, состояние имеет имя"a", а индекс с нуля в рекуррентной последовательности имеет имя"n". Переданная строка должна возвращать желаемое значение дляa[n]при заданныхa[n - 1],a[n - 2],a[n - 3],...,a[n - stateSize]. Размер состояния определяется количеством аргументов, переданных в вызовrecurrence. СтруктураRecurrenceсама заботится о управлении состоянием рекуррентной последовательности и его соответствующем смещении.- Примеры:
-
import std.algorithm.comparison : equal; // The Fibonacci numbers, using function in string form: // a[0] = 1, a[1] = 1, and compute a[n+1] = a[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])); // The factorials, using function in lambda form: 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 ])); // The triangular numbers, using function in explicit form: 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); writeln(odds.front); // 1 odds.popFront(); writeln(odds.front); // 3 odds.popFront(); writeln(odds.front); // 5
- Примеры:
- Треугольные числа, используя функцию в лямбда-форме:
auto tri = sequence!((a,n) => n*(n+1)/2)(); // Note random access writeln(tri[0]); // 0 writeln(tri[3]); // 6 writeln(tri[1]); // 1 writeln(tri[4]); // 10 writeln(tri[2]); // 3
- Примеры:
- Числа Фибоначчи, используя функцию в явном виде:
import std.math : pow, round, sqrt; static ulong computeFib(S)(S state, size_t n) { // Binet's formula return cast(ulong)(round((pow(state[0], n+1) - pow(state[1], n+1)) / state[2])); } auto fib = sequence!computeFib( (1.0 + sqrt(5.0)) / 2.0, // Golden Ratio (1.0 - sqrt(5.0)) / 2.0, // Conjugate of Golden Ratio sqrt(5.0)); // Note random access with [] operator writeln(fib[1]); // 1 writeln(fib[4]); // 5 writeln(fib[3]); // 3 writeln(fib[2]); // 2 writeln(fib[9]); // 55
- auto iota(B, E, S)(B begin, E end, S step)
Constraints: if ((isIntegral!(CommonType!(B, E)) || isPointer!(CommonType!(B, E))) && isIntegral!S);
auto iota(B, E)(B begin, E end)
Constraints: if (isFloatingPoint!(CommonType!(B, E)));
auto iota(B, E)(B begin, E end)
Constraints: if (isIntegral!(CommonType!(B, E)) || isPointer!(CommonType!(B, E)));
auto iota(E)(E end)
Constraints: if (is(typeof(iota(E(0), end))));
auto iota(B, E, S)(B begin, E end, S step)
Constraints: if (isFloatingPoint!(CommonType!(B, E, S)));
auto iota(B, E)(B begin, E end)
Constraints: 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— ошибка. Для встроенных типов возвращаемый диапазон — диапазон с произвольным доступом. Для пользовательских типов, поддерживающих++, диапазон является диапазоном ввода. Целочисленный iota также поддерживает операторinсправа. Он учитывает шаг, целочисленный тип не будет считаться содержащимся, если он попадает между двумя последовательными значениями диапазона.containsделает то же самое, но слева.
- Пример
void main() { import std.stdio; // The following groups all produce the same output of: // 0 1 2 3 4 foreach (i; 0 .. 5) writef("%s ", i); writeln(); import std.range : iota; foreach (i; iota(0, 5)) writef("%s ", i); writeln(); writefln("%(%s %|%)", iota(0, 5)); import std.algorithm.iteration : map; import std.algorithm.mutation : copy; import std.format; iota(0, 5).map!(i => format("%s ", i)).copy(stdout.lockingTextWriter()); writeln(); }- Примеры:
-
import std.algorithm.comparison : equal; import std.math : approxEqual; auto r = iota(0, 10, 1); assert(equal(r, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9])); assert(equal(r, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9])); assert(3 in r); assert(r.contains(3)); //Same as above assert(!(10 in r)); assert(!(-8 in r)); r = iota(0, 11, 3); assert(equal(r, [0, 3, 6, 9])); writeln(r[2]); // 6 assert(!(2 in r)); auto rf = iota(0.0, 0.5, 0.1); assert(approxEqual(rf, [0.0, 0.1, 0.2, 0.3, 0.4]));
- enum TransverseOptions: int;
-
Параметры для диапазонов
FrontTransversalиTransversal(ниже).- Примеры:
-
import std.algorithm.comparison : equal; import std.exception : assertThrown; auto arr = [[1, 2], [3, 4, 5]]; auto r1 = arr.frontTransversal!(TransverseOptions.assumeJagged); assert(r1.equal([1, 3])); // throws on construction assertThrown!Exception(arr.frontTransversal!(TransverseOptions.enforceNotJagged)); auto r2 = arr.frontTransversal!(TransverseOptions.assumeNotJagged); assert(r2.equal([1, 3])); // either assuming or checking for equal lengths makes // the result a random access range writeln(r2[0]); // 1 static assert(!__traits(compiles, r1[0]));
- assumeJagged
-
При обходе элементы диапазона диапазонов предполагаются с разной длиной (например, неровный массив).
- enforceNotJagged
-
Обход требует, чтобы элементы диапазона диапазонов имели одинаковую длину (например, массив массивов, все с одинаковой длиной). Проверка выполняется один раз при построении диапазона обхода.
- assumeNotJagged
-
Обход предполагает (без проверки), что элементы диапазона диапазонов имеют одинаковую длину. Этот параметр полезен, если проверка уже выполнена снаружи диапазона.
- 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);
-
Конструирование из входных данных.
- 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); -
Примитив произвольного доступа. Он предоставляется, если
isRandomAccessRange!RangeOfRanges && (opt == TransverseOptions.assumeNotJagged || opt == TransverseOptions.enforceNotJagged). - typeof(this) opSlice(size_t lower, size_t upper);
-
Вырезка, если предоставляется, если
RangeOfRangesподдерживает вырезку и все условия для поддержки индексации выполнены.
- struct Transversal(Ror, TransverseOptions opt = TransverseOptions.assumeJagged);
Transversal!(RangeOfRanges, opt) transversal(TransverseOptions opt = TransverseOptions.assumeJagged, RangeOfRanges)(RangeOfRanges rr, size_t n);
-
При заданном диапазоне диапазонов, итерируйте поперечно через
n-й элемент каждого из вложенных диапазонов. Эта функция похожа наunzipв других языках.- Параметры:
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 ]));
- Примеры:
- Следующий код выполняет полное распаковку
import std.algorithm.comparison : equal; import std.algorithm.iteration : map; int[][] y = [[1, 2, 3], [4, 5, 6]]; auto z = y.front.walkLength.iota.map!(i => transversal(y, i)); assert(equal!equal(z, [[1, 4], [2, 5], [3, 6]]));
- this(RangeOfRanges input, size_t n);
-
Конструктор из входных данных и индекса.
- enum bool empty;
@property ref auto front();
E moveFront();
@property void front(E val);
void popFront();
@property typeof(this) save(); -
Примитивы диапазонов вперёд.
- @property ref auto back();
void popBack();
E moveBack();
@property void back(E val); -
Двунаправленные примитивы. Они предлагаются, если
isBidirectionalRange!RangeOfRanges. - ref auto opIndex(size_t n);
E moveAt(size_t n);
void opIndexAssign(E val, size_t n); -
Примитив произвольного доступа. Он предлагается, если
isRandomAccessRange!RangeOfRanges && (opt == TransverseOptions.assumeNotJagged || opt == TransverseOptions.enforceNotJagged). - typeof(this) opSlice(size_t lower, size_t upper);
-
Операция слайсинга, если
RangeOfRangesподдерживает слайсинг и выполнены все условия для поддержки индексирования.
- Transposed!(RangeOfRanges, opt) transposed(TransverseOptions opt = TransverseOptions.assumeJagged, RangeOfRanges)(RangeOfRanges rr)
Constraints: if (isForwardRange!RangeOfRanges && isInputRange!(ElementType!RangeOfRanges) && hasAssignableElements!RangeOfRanges); -
При заданном диапазоне диапазонов возвращает диапазон диапазонов, где i-й поддиапазон содержит i-й элемент исходных поддиапазонов.
Transposedв настоящее время определяетsave, но не работает как диапазон вперёд. Потребление копии, созданной с помощьюsave, потребляет все копии, даже исходные поддиапазоны, поданные вTransposed.- Параметры:
opt Управляет предположениями, которые функция делает о длине диапазонов (например, зубчатые или нет) RangeOfRanges rrДиапазон диапазонов
- Примеры:
-
import std.algorithm.comparison : equal; int[][] ror = [ [1, 2, 3], [4, 5, 6] ]; auto xp = transposed(ror); assert(equal!"a.equal(b)"(xp, [ [1, 4], [2, 5], [3, 6] ]));
- Примеры:
-
int[][] x = new int[][2]; x[0] = [1, 2]; x[1] = [3, 4]; auto tr = transposed(x); int[][] witness = [ [ 1, 3 ], [ 2, 4 ] ]; uint i; foreach (e; tr) { writeln(array(e)); // witness[i++] }
- 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); -
Этот struct принимает два диапазона,
sourceиindices, и создаёт представлениеsourceкак если бы его элементы были переупорядочены в соответствии сindices.indicesможет включать только подмножество элементовsourceи может также повторять элементы.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]));
- @property ref auto front();
void popFront();
@property typeof(this) save();
@property ref auto front(ElementType!Source newVal);
auto moveFront();
@property ref auto back();
void popBack();
@property ref auto back(ElementType!Source newVal);
auto moveBack();
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();
-
Возвращает исходный диапазон.
- @property Indices indices();
-
Возвращает диапазон индексов.
- size_t physicalIndex(size_t logicalIndex);
-
Возвращает физический индекс в исходном диапазоне, соответствующий заданному логическому индексу. Это полезно, например, при индексировании
Indexedбез добавления другого уровня косвенности.- Примеры:
-
auto ind = indexed([1, 2, 3, 4, 5], [1, 3, 4]); writeln(ind.physicalIndex(0)); // 1
- struct Chunks(Source) if (isInputRange!Source);
Chunks!Source chunks(Source)(Source source, size_t chunkSize)
Constraints: if (isInputRange!Source); -
Этот диапазон итерируется по частям фиксированного размера
chunkSizeдиапазонаsource.Sourceдолжен быть диапазоном ввода.chunkSizeдолжно быть больше нуля.Если
!isInfinite!Sourceиsource.walkLengthне делится нацело наchunkSize, последний элемент этого диапазона будет содержать меньше чемchunkSizeэлементов.
ЕслиSourceявляется диапазоном вперёд, результирующий диапазон также будет диапазонами вперёд. В противном случае, результирующие части будут диапазонами ввода, потребляющими тот же ввод: итерирование поfrontуменьшит часть таким образом, что последующие вызовыfrontбольше не будут возвращать полную часть, и вызовpopFrontна внешнем диапазоне сделает недействительными любые оставшиеся ссылки на предыдущие значенияfront.- Параметры:
Source sourceДиапазон, из которого будут выбраны части size_t chunkSizeРазмер части
- См. также:
-
slide
- Возвращает:
- Диапазон частей.
- Примеры:
-
import std.algorithm.comparison : equal; auto source = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; auto chunks = chunks(source, 4); writeln(chunks[0]); // [1, 2, 3, 4] writeln(chunks[1]); // [5, 6, 7, 8] writeln(chunks[2]); // [9, 10] writeln(chunks.back); // chunks[2] writeln(chunks.front); // chunks[0] writeln(chunks.length); // 3 assert(equal(retro(array(chunks)), array(retro(chunks))));
- Примеры:
- Поддерживаются диапазоны ввода, не являющиеся диапазонами вперёд, но с ограниченной семантикой.
import std.algorithm.comparison : equal; int i; // The generator doesn't save state, so it cannot be a forward range. auto inputRange = generate!(() => ++i).take(10); // We can still process it in chunks, but it will be single-pass only. auto chunked = inputRange.chunks(2); assert(chunked.front.equal([1, 2])); assert(chunked.front.empty); // Iterating the chunk has consumed it chunked.popFront; assert(chunked.front.equal([3, 4]));
- this(Source source, size_t chunkSize);
-
Стандартный конструктор
- @property auto front();
void popFront();
@property bool empty(); -
Примитивы диапазона ввода. Всегда присутствуют.
- @property typeof(this) save();
-
Примитивы диапазона вперёд. Присутствуют только если
Sourceявляется диапазоном вперёд. - @property size_t length();
-
Длина. Только если
hasLength!Sourceявляетсяtrue - auto opIndex(size_t index);
typeof(this) opSlice(size_t lower, size_t upper); -
Операции индексирования и слайсинга. Предоставляются только если
hasSlicing!Sourceявляетсяtrue. - @property auto back();
void popBack(); -
Двунаправленные примитивы диапазонов. Предоставляются только если как
hasSlicing!Source, так иhasLength!Sourceявляютсяtrue.
- struct EvenChunks(Source) if (isForwardRange!Source && hasLength!Source);
EvenChunks!Source evenChunks(Source)(Source source, size_t chunkCount)
Constraints: if (isForwardRange!Source && hasLength!Source); -
Этот диапазон разбивает диапазон
sourceнаchunkCountчасти приблизительно равной длины.Sourceдолжен быть диапазоном вперёд с известной длиной.В отличие от
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); writeln(chunks[0]); // [1, 2, 3, 4] writeln(chunks[1]); // [5, 6, 7] writeln(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являетсяtrue.
- auto slide(Flag!"withPartial" f = Yes.withPartial, Source)(Source source, size_t windowSize, size_t stepSize = 1)
Constraints: if (isForwardRange!Source); -
Итерация с фиксированным размером скользящего окна размером
windowSizeпо диапазонуsourceс помощью пользовательскогоstepSize.Диапазон
Sourceдолжен быть как минимум ForwardRange, аwindowSizeдолжно быть больше нуля.
ДляwindowSize = 1он разбивает диапазон на группы по одному элементу (также известные какunflatten) ДляwindowSize = 2он аналогиченzip(source, source.save.dropOne).- Параметры:
f Указывает, следует ли игнорировать последний элемент, если в нём меньше элементов, чем windowSize(No.withPartial) или добавить его (Yes.withPartial)Source sourceДиапазон, из которого будет выбран слайс size_t windowSizeРазмер скользящего окна size_t stepSizeШаг между окнами (по умолчанию 1)
- Возвращает:
- Диапазон всех скользящих окон с проинициализированной двунаправленностью, вперёд, произвольным доступом и слайсингом.
- Примечание
- Для избежания накладных расходов на производительность, двунаправленность доступна только тогда, когда
std.range.primitives.hasSlicingиstd.range.primitives.hasLengthявляются истинными.
- См. также:
chunks
- Примеры:
- Итерирование по диапазонам с окнами
import std.algorithm.comparison : equal; assert([0, 1, 2, 3].slide(2).equal!equal( [[0, 1], [1, 2], [2, 3]] )); assert(5.iota.slide(3).equal!equal( [[0, 1, 2], [1, 2, 3], [2, 3, 4]] ));
- Примеры:
- Установите пользовательский шаг (по умолчанию 1)
import std.algorithm.comparison : equal; assert(6.iota.slide(1, 2).equal!equal( [[0], [2], [4]] )); assert(6.iota.slide(2, 4).equal!equal( [[0, 1], [4, 5]] )); assert(iota(7).slide(2, 2).equal!equal( [[0, 1], [2, 3], [4, 5], [6]] )); assert(iota(12).slide(2, 4).equal!equal( [[0, 1], [4, 5], [8, 9]] ));
- Примеры:
- Разрешить последнему слайсу иметь меньше элементов, чем windowSize
import std.algorithm.comparison : equal; assert(3.iota.slide!(No.withPartial)(4).empty); assert(3.iota.slide!(Yes.withPartial)(4).equal!equal( [[0, 1, 2]] ));
- Примеры:
- Подсчитать все возможные подстроки длиной 2
import std.algorithm.iteration : each; int[dstring] d; "AGAGA"d.slide!(Yes.withPartial)(2).each!(a => d[a]++); writeln(d); // ["AG"d:2, "GA"d:2]
- Примеры:
- withPartial имеет эффект только в том случае, если последний элемент в диапазоне не имеет полного размера
import std.algorithm.comparison : equal; assert(5.iota.slide!(Yes.withPartial)(3, 4).equal!equal([[0, 1, 2], [4]])); assert(6.iota.slide!(Yes.withPartial)(3, 4).equal!equal([[0, 1, 2], [4, 5]])); assert(7.iota.slide!(Yes.withPartial)(3, 4).equal!equal([[0, 1, 2], [4, 5, 6]])); assert(5.iota.slide!(No.withPartial)(3, 4).equal!equal([[0, 1, 2]])); assert(6.iota.slide!(No.withPartial)(3, 4).equal!equal([[0, 1, 2]])); assert(7.iota.slide!(No.withPartial)(3, 4).equal!equal([[0, 1, 2], [4, 5, 6]]));
- auto only(Values...)(return scope Values values)
Constraints: if (!is(CommonType!Values == void) || Values.length == 0); -
Сборка
valuesв диапазон, содержащий все его элементы in-situ.Полезно, когда одно значение или несколько разрозненных значений должны быть переданы алгоритму, ожидающему диапазон, без динамического выделения памяти.
Поскольку копирование диапазона означает копирование всех элементов, его можно безопасно возвращать из функций. По той же причине копирование возвращенного диапазона может быть дорогостоящим для большого количества аргументов.- Параметры:
Values valuesзначения для сборки вместе
- Возвращает:
- Диапазон собранных значений.
- См. также:
-
chainдля объединения диапазонов
- Примеры:
-
import std.algorithm.comparison : equal; import std.algorithm.iteration : filter, joiner, map; import std.algorithm.searching : findSplitBefore; import std.uni : isUpper; assert(equal(only('♡'), "♡")); writeln([1, 2, 3, 4].findSplitBefore(only(3))[0]); // [1, 2] assert(only("one", "two", "three").joiner(" ").equal("one two three")); string title = "The D Programming Language"; assert(title .filter!isUpper // take the upper case letters .map!only // make each letter its own range .joiner(".") // join the ranges together lazily .equal("T.D.P.L"));
- auto enumerate(Enumerator = size_t, Range)(Range range, Enumerator start = 0)
Constraints: 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 в любом порядке. Следующий код должен компилироваться:(ref T1 a, ref T2 b) { fn(a, b); fn(b, a); }- Примеры:
-
void func1(int a, int b); void func2(int a, float b); static assert(isTwoWayCompatible!(func1, int, int)); static assert(isTwoWayCompatible!(func1, short, int)); static assert(!isTwoWayCompatible!(func2, int, float)); void func3(ref int a, ref int b); static assert( isTwoWayCompatible!(func3, int, int)); static assert(!isTwoWayCompatible!(func3, short, int));
- enum SearchPolicy: int;
-
Политика, используемая с примитивами поиска
lowerBound,upperBound, иequalRangeизSortedRangeниже.- Примеры:
-
import std.algorithm.comparison : equal; auto a = assumeSorted([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]); auto p1 = a.upperBound!(SearchPolicy.binarySearch)(3); assert(p1.equal([4, 5, 6, 7, 8, 9])); auto p2 = a.lowerBound!(SearchPolicy.gallop)(4); assert(p2.equal([0, 1, 2, 3]));
- linear
-
Поиск линейным способом.
- trot
-
Поиск с шагом, который линейно возрастает (1, 2, 3,...), что приводит к квадратичному графику поиска (используемые индексы 0, 1, 3, 6, 10, 15, 21, 28,...). После того, как поиск переходит через целевое значение, оставшийся интервал ищется с помощью бинарного поиска. Поиск завершается за время Ο(
sqrt(n)). Используйте его, когда вы с достаточной уверенностью знаете, что значение находится примерно в начале диапазона. - gallop
-
Выполняет алгоритм поиска галопом, т.е. поиск с шагом, который удваивается каждый раз (1, 2, 4, 8,...), что приводит к экспоненциальному графику поиска (используемые индексы 0, 1, 3, 7, 15, 31, 63,...). После того, как поиск переходит через целевое значение, оставшийся интервал ищется с помощью бинарного поиска. Значение находится за время Ο(
log(n)). - binarySearch
-
Поиск с помощью классической политики деления интервала пополам. Поиск начинается посередине диапазона, и на каждом шаге поиска диапазон делится пополам. Эта политика находит значение за время Ο(
log(n)), но менее дружелюбна к кешу, чемgallopдля больших диапазонов. ПолитикаbinarySearchиспользуется в качестве последнего шага дляtrot,gallop,trotBackwards, иgallopBackwardsстратегий. - trotBackwards
-
Аналогично
trot, но начинается в обратном направлении. Используйте его, когда уверены, что значение находится примерно в конце диапазона. - gallopBackwards
-
Аналогично
gallop, но начинается в обратном направлении. Используйте его, когда уверены, что значение находится примерно в конце диапазона.
- enum SortedRangeOptions: int;
-
Параметры для
SortedRangeдиапазонов (ниже).- Примеры:
-
// create a SortedRange, that's checked strictly SortedRange!(int[],"a < b", SortedRangeOptions.checkStrictly)([ 1, 3, 5, 7, 9 ]);
- assumeSorted
-
Предполагается, что диапазон отсортирован без проверки.
- checkStrictly
-
Все элементы диапазона проверяются на отсортированность. Проверка выполняется за время O(n).
- checkRoughly
-
Некоторые элементы диапазона проверяются на отсортированность. Для диапазонов с произвольным порядком это, почти наверняка, обнаружит, что он не отсортирован. Для почти отсортированных диапазонов вероятность неудачи выше. Проверяемые элементы выбираются детерминированным образом, что делает эту проверку воспроизводимой. Проверка выполняется за время O(log(n)).
- struct SortedRange(Range, alias pred = "a < b", SortedRangeOptions opt = SortedRangeOptions.assumeSorted) if (isInputRange!Range && !isInstanceOf!(SortedRange, Range));
template SortedRange(Range, alias pred = "a < b", SortedRangeOptions opt = SortedRangeOptions.assumeSorted) if (isInstanceOf!(SortedRange, 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(!(32 in r)); auto r1 = sort!"a > b"(a); assert(3 in r1); assert(!r1.contains(32)); writeln(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]); // illegal to break sortedness of original range assert(!r.contains(42)); // passes although it shouldn't
- @property bool empty();
@property auto save();
@property ref auto front();
void popFront();
@property ref auto back();
void popBack();
ref auto opIndex(size_t i);
scope auto opSlice(size_t a, size_t b) return; -
Базовые операции с диапазонами.
- auto release();
-
Освобождает управляемый диапазон и возвращает его.
- auto lowerBound(SearchPolicy sp = SearchPolicy.binarySearch, V)(V value)
Constraints: if (isTwoWayCompatible!(predFun, ElementType!Range, V) && hasSlicing!Range); -
Эта функция использует поиск с политикой
spдля нахождения наибольшего левого поддиапазона, на которомpred(x, value)являетсяtrueдля всехx(например, еслиpred— "меньше", возвращает часть диапазона с элементами, строго меньшимиvalue). Расписание поиска и его сложность описаны вSearchPolicy.- Примеры:
-
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)
Constraints: if (isTwoWayCompatible!(predFun, ElementType!Range, V)); -
Эта функция ищет с политикой
spдля нахождения наибольшего правого поддиапазона, на которомpred(value, x)являетсяtrueдля всехx(например, еслиpred— "меньше", возвращает часть диапазона с элементами, строго большимиvalue). Расписание поиска и его сложность описаны вSearchPolicy.Для диапазонов, которые не поддерживают случайный доступ, разрешена только политика
SearchPolicy.linear(и она должна быть указана явно, чтобы не подвергать код пользователя неожиданным неэффективностям). Для поисков с случайным доступом разрешены все политики, иSearchPolicy.binarySearchявляется по умолчанию.- Примеры:
-
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)
Constraints: if (isTwoWayCompatible!(predFun, ElementType!Range, V) && isRandomAccessRange!Range); -
Возвращает поддиапазон, содержащий все элементы
e, для которых какpred(e, value), так иpred(value, e)возвращаютfalse(например, еслиpred— "меньше", возвращает часть диапазона с элементами, равнымиvalue). Использует классический бинарный поиск с делением интервала пополам, пока не найдёт значение, удовлетворяющее условию, затем используетSearchPolicy.gallopBackwardsдля нахождения левой границы иSearchPolicy.gallopдля нахождения правой границы. Эти политики оправданы тем, что обе границы, скорее всего, будут находиться рядом с первым найденным значением (т. е. диапазоны с равными элементами относительно малы). Завершает весь поиск за Ο(log(n)) времени.- Примеры:
-
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)
Constraints: if (isTwoWayCompatible!(predFun, ElementType!Range, V) && isRandomAccessRange!Range && hasLength!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)
Constraints: if (isRandomAccessRange!Range); -
Возвращает
trueтогда и только тогда, когдаvalueможно найти вrange, который предполагается отсортированным. Выполняет Ο(log(r.length)) вычисленийpred. - bool opBinaryRight(string op, V)(V value)
Constraints: if (op == "in" && isRandomAccessRange!Range); -
Подобно
contains, но значение указано перед диапазоном. - auto groupBy()();
-
Возвращает диапазон поддиапазонов элементов, которые эквивалентны согласно отношению сортировки.
- auto assumeSorted(alias pred = "a < b", R)(R r)
Constraints: if (isInputRange!(Unqual!R)); -
Предполагает, что
rотсортирован по предикатуpredи возвращает соответствующийSortedRange!(pred, R), использующийrв качестве поддержки. Для проверки отсортированности со стоимостью Ο(n) используйтеstd.algorithm.sorting.isSorted.- Примеры:
-
import std.algorithm.comparison : equal; int[] a = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; auto p = assumeSorted(a); assert(equal(p.lowerBound(4), [0, 1, 2, 3])); assert(equal(p.lowerBound(5), [0, 1, 2, 3, 4])); assert(equal(p.lowerBound(6), [0, 1, 2, 3, 4, 5])); assert(equal(p.lowerBound(6.9), [0, 1, 2, 3, 4, 5, 6]));
- struct RefRange(R) if (isInputRange!R);
auto refRange(R)(R* range)
Constraints: if (isInputRange!R);
-
Обёртка, которая эффективно позволяет передавать диапазон по ссылке. И исходный диапазон, и RefRange всегда будут содержать точно такие же элементы. Любое действие, выполненное с одним из них, повлияет на другой. Например, если он передаётся в функцию, которая неявно копирует исходный диапазон при его передаче, исходный диапазон не копируется, а потребляется как тип ссылочного типа.
- Примечание
-
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); writeln(found1); // [45, 12, 22] writeln(buffer); // [1, 9, 45, 12, 22] auto wrapped1 = refRange(&buffer); auto found2 = find(wrapped1, 45); writeln(*found2.ptr); // [45, 12, 22] writeln(buffer); // [45, 12, 22] auto found3 = find(wrapped1.save, 22); writeln(*found3.ptr); // [22] writeln(buffer); // [45, 12, 22] string str = "hello world"; auto wrappedStr = refRange(&str); writeln(str.front); // 'h' str.popFrontN(5); writeln(str); // " world" writeln(wrappedStr.front); // ' ' writeln(*wrappedStr.ptr); // " world"
- Примеры:
- Пример 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; //Everything points to the same stuff as before. assert(wrapped1.ptr is &buffer1); assert(wrapped2.ptr is &buffer2); assert(wrapped1.ptr !is wrapped2.ptr); //But buffer1 has changed due to the assignment. writeln(buffer1); // [6, 7, 8, 9, 10] writeln(buffer2); // [6, 7, 8, 9, 10] buffer2 = [11, 12, 13, 14, 15]; //Everything points to the same stuff as before. assert(wrapped1.ptr is &buffer1); assert(wrapped2.ptr is &buffer2); assert(wrapped1.ptr !is wrapped2.ptr); //But buffer2 has changed due to the assignment. writeln(buffer1); // [6, 7, 8, 9, 10] writeln(buffer2); // [11, 12, 13, 14, 15] wrapped2 = null; //The pointer changed for wrapped2 but not wrapped1. assert(wrapped1.ptr is &buffer1); assert(wrapped2.ptr is null); assert(wrapped1.ptr !is wrapped2.ptr); //buffer2 is not affected by the assignment. writeln(buffer1); // [6, 7, 8, 9, 10] writeln(buffer2); // [11, 12, 13, 14, 15]
- pure nothrow @safe this(R* range);
- auto opAssign(RefRange rhs);
-
Это не присваивает указатель
rhsэтомуRefRange. Вместо этого, он присваивает диапазон, на который указываетrhs, диапазону, на который указывает этотRefRange. Это потому, что любое действие надRefRangeтакое же, как если бы оно происходило с исходным диапазоном. Единственное исключение — когдаRefRangeприсваиваетсяnullнапрямую или потому, чтоrhsявляетсяnull. В этом случаеRefRangeбольше не ссылается на исходный диапазон, а являетсяnull. - void 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();
auto opSlice();
const auto opSlice(); -
Определено только если
isForwardRange!Rявляетсяtrue. - @property auto back();
const @property auto back();
@property auto back(ElementType!R value);
void popBack(); -
Определено только если
isBidirectionalRange!Rявляетсяtrue. - ref auto opIndex(IndexType)(IndexType index);
const ref auto opIndex(IndexType)(IndexType index); -
Определено только если
isRandomAccesRange!Rявляетсяtrue. - auto moveFront();
-
Определено только если
hasMobileElements!RиisForwardRange!Rявляютсяtrue. - auto moveBack();
-
Определено только если
hasMobileElements!RиisBidirectionalRange!Rявляютсяtrue. - auto moveAt(size_t index);
-
Определено только если
hasMobileElements!RиisRandomAccessRange!Rявляютсяtrue. - @property size_t length();
const @property size_t length();
alias opDollar = length; -
Определено только если
hasLength!Rявляетсяtrue. - auto opSlice(IndexType1, IndexType2)(IndexType1 begin, IndexType2 end);
const auto opSlice(IndexType1, IndexType2)(IndexType1 begin, IndexType2 end); -
Определено только если
hasSlicing!Rявляетсяtrue.
- auto bitwise(R)(auto ref R range)
Constraints: if (isInputRange!R && isIntegral!(ElementType!R)); -
Битовый адаптер над диапазоном целочисленных типов. Потребляет элементы диапазона побитово, от младшего бита к старшему.
- Параметры:
R целочисленный входной диапазон для итерации R rangeдиапазон для побитовой обработки
- Возвращаемое значение:
- A
Bitwiseвходной диапазон с распространёнными возможностями прямой, двунаправленной и произвольной итерации
- Примеры:
-
import std.algorithm.comparison : equal; import std.format : format; // 00000011 00001001 ubyte[] arr = [3, 9]; auto r = arr.bitwise; // iterate through it as with any other range writeln(format("%(%d%)", r)); // "1100000010010000" assert(format("%(%d%)", r.retro).equal("1100000010010000".retro)); auto r2 = r[5 .. $]; // set a bit r[2] = 1; writeln(arr[0]); // 7 writeln(r[5]); // r2[0]
- Примеры:
- Можно использовать bitwise для реализации однородного генератора bool
import std.algorithm.comparison : equal; import std.random : rndGen; auto rb = rndGen.bitwise; static assert(isInfinite!(typeof(rb))); auto rb2 = rndGen.bitwise; // Don't forget that structs are passed by value assert(rb.take(10).equal(rb2.take(10)));
- struct NullSink;
ref auto nullSink(); -
OutputRange, который отбрасывает получаемые данные.
- Примеры:
-
import std.algorithm.iteration : map; import std.algorithm.mutation : copy; [4, 5, 6].map!(x => x * 2).copy(nullSink); // data is discarded
- Примеры:
-
import std.csv : csvNextToken; string line = "a,b,c"; // ignore the first column line.csvNextToken(nullSink, ',', '"'); line.popFront; // look at the second column Appender!string app; line.csvNextToken(app, ',', '"'); writeln(app.data); // "b"
- auto tee(Flag!"pipeOnPop" pipeOnPop = Yes.pipeOnPop, R1, R2)(R1 inputRange, R2 outputRange)
Constraints: if (isInputRange!R1 && isOutputRange!(R2, ElementType!R1));
auto tee(alias fun, Flag!"pipeOnPop" pipeOnPop = Yes.pipeOnPop, R1)(R1 inputRange)
Constraints: if (is(typeof(fun) == void) || isSomeFunction!fun); -
Реализует "tee"-стиль конвейера, оборачивая входной диапазон таким образом, чтобы элементы диапазона могли передаваться в предоставленную функцию или
OutputRangeпо мере итерации. Это полезно для вывода промежуточных значений в длинной цепочке кода диапазонов, выполнения некоторого действия с побочными эффектами при каждом вызовеfrontилиpopFront, или перенаправления элементов диапазона в вспомогательныйOutputRange.Важно отметить, что поскольку результирующий диапазон оценивается лениво, в случае версии
tee, принимающей функцию, функция фактически не будет выполнена до тех пор, пока диапазон не будет "пройден" с помощью функций, оценивающих диапазоны, таких какstd.array.arrayилиstd.algorithm.iteration.fold.- Параметры:
pipeOnPop Если Yes.pipeOnPop, простое итеративное прохождение диапазона без вызоваfrontдостаточно, чтобыteeотражал элементы вoutputRange(или, соответственно,fun). Обратите внимание, что каждый вызовpopFront()будет отражать старое значениеfront, а не новое. Это означает, что последнее значение не будет передано, если диапазон не будет итерироваться до пустого состояния. ЕслиNo.pipeOnPop, только те элементы, для которыхfrontбудет вызван, также будут отправлены вoutputRange/fun. Еслиfrontвызывается дважды для одного и того же элемента, он всё равно будет отправлен только один раз. Если это кэширование нежелательно, используйтеstd.algorithm.iteration.mapвместо этого.R1 inputRangeВходной диапазон, передаваемый. R2 outputRangeЭтот диапазон будет получать элементы inputRangeпоэтапно по мере продвижения итерации.fun Эта функция будет вызываться с элементами inputRangeпоэтапно по мере продвижения итерации.
- Возвращаемое значение:
- Входной диапазон, предоставляющий элементы
inputRange. Независимо от того, является лиinputRangeболее мощным диапазоном (прямой, двунаправленный и т. д.), результатом всегда является входной диапазон. Чтение этого вызывает итерациюinputRangeи возвращает его элементы по очереди. Кроме того, те же элементы будут передаваться вoutputRangeилиfun.
- См. также:
std.algorithm.iteration.each
- Примеры:
-
import std.algorithm.comparison : equal; import std.algorithm.iteration : filter, map; // Sum values while copying int[] values = [1, 4, 9, 16, 25]; int sum = 0; auto newValues = values.tee!(a => sum += a).array; assert(equal(newValues, values)); writeln(sum); // 1 + 4 + 9 + 16 + 25 // Count values that pass the first filter int count = 0; auto newValues4 = values.filter!(a => a < 10) .tee!(a => count++) .map!(a => a + 1) .filter!(a => a < 10); //Fine, equal also evaluates any lazy ranges passed to it. //count is not 3 until equal evaluates newValues4 assert(equal(newValues4, [2, 5])); writeln(count); // 3
- auto padLeft(R, E)(R r, E e, size_t n)
Constraints: 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 относительно длины строк, которая не является количеством символов или графем, а количеством единиц кодирования. Если вы хотите рассматривать каждую графему как имеющую длину только в одну единицу кодирования, вызовитеstd.uni.byGraphemeперед вызовом этой функции.
Если уrесть длина, то это Ο(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)
Constraints: 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___"));
© 1999–2021 The D Language Foundation
Licensed under the Boost License 1.0.
https://dlang.org/phobos/std_range.html