Переместиться к: 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
для изучения основ работы с ними и создания кода, основанного на диапазонах.
Подмодули: Этот модуль имеет два подмодуля:
Подмодуль 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 диапазонов, создаёт диапазон, который последовательно возвращает кортеж всех первых элементов, кортеж всех вторых элементов, и т.д. |
Исходный код: std/range/package.d
retro
(Range)(Range r
)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);
stride
(Range)(Range r
, size_t n
)r
с шагом n
.
Если диапазон r
— это диапазон с произвольным доступом, перемещения производятся с помощью индексов в диапазоне;
в противном случае перемещения производятся через последовательные вызовы popFront. Применение stride
дважды к тому же диапазону даст результат stride
с шагом, равным произведению двух применений. Если n
равно 0, это приводит к ошибке.
Range r |
входной диапазон, к которому применяется stride
|
size_t n |
количество пропускаемых элементов |
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));
chain
(Ranges...)(Ranges rs
)chain
принимает любое количество диапазонов и возвращает объект Chain!(R1, R2,...). Диапазоны могут быть различными, но они должны иметь один и тот же тип элемента. Результат является диапазоном, в котором есть примитивы front, popFront, и empty. Если во всех диапазонах есть произвольный доступ и length, 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]));
choose
(R1, R2)(bool condition
, R1 r1
, R2 r2
)condition
.
bool condition |
какой диапазон выбрать: r1 если true , r2 иначе |
R1 r1 |
"true " диапазон |
R2 r2 |
"false " диапазон |
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 ]));
chooseAmong
(Ranges...)(size_t index
, Ranges rs
)rs
[0], rs
[1]))) && is(typeof(chooseAmong
(0, rs
[1..$]))));
chooseAmong
(Ranges...)(size_t index
, Ranges rs
)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); }
roundRobin
(Rs...)(Rs 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]));
radial
(Range, I)(Range r
, I startingIndex
)radial
(R)(R 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
Take
(Range)
if (isInputRange!(Unqual!Range) && !(!isInfinite!(Unqual!Range)
&& hasSlicing!(Unqual!Range) || is(Range T == Take
!T)));
Переместиться к: 2
take
(R)(R input
, size_t n
)n
элементов диапазона. Это особенно полезно при использовании с бесконечными диапазонами.
take
не требует наличия n
или больше элементов в r. Как следствие, информация о длине отсутствует в результирующем диапазоне, если r также не имеет информацию о длине.
r | входной диапазон, по которому надо итерировать вплоть до n раз |
size_t n |
количество требуемых элементов |
take
их также предложит.source
;
empty
();
Переместиться к: 2
front
();
popFront
();
save
();
front
(ElementType!R v
);
moveFront
();
length
();
opDollar
= length;
opSlice
()(size_t i
, size_t j
)popBack
();
Переместиться к: 2
back
();
opIndex
(size_t index
);
back
(ElementType!R v
);
opIndexAssign
(ElementType!R v
, size_t index
);
moveBack
();
moveAt
(size_t index
);
maxLength
();
Замечание:
фактическая длина диапазона зависит от диапазона, лежащего в основе. Если он имеет меньше элементов, он остановится прежде, чем maxLength
будет достигнут.
Take
(R) if (isInputRange!(Unqual!R) && (!isInfinite!(Unqual!R) && hasSlicing!(Unqual!R) || is(R T == Take
!T)))take
(R)(R input
, size_t n
)take
(R)(R input
, size_t n
)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 ]));
takeExactly
(R)(R range
, size_t n
)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);
takeOne
(R)(R source
)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);
auto range = takeNone!(int[])(); assert(range.length == 0); assert(range.empty);
takeNone
(R)(R range
)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);
tail
(Range)(Range range
, size_t n
)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"));
drop
(R)(R range
, size_t n
)dropBack
(R)(R range
, size_t n
)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 "));
dropExactly
(R)(R range
, size_t n
)dropBackExactly
(R)(R range
, size_t 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]));
dropOne
(R)(R range
)dropBackOne
(R)(R range
)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]));
value
.
T value |
величина для повторения |
import std.algorithm.comparison : equal; assert(equal(5.repeat().take(4), [ 5, 5, 5, 5 ]));
front
();
back
();
empty
;
popFront
();
popBack
();
save
();
opIndex
(size_t);
Переместиться к: 2
opSlice
(size_t i
, size_t j
);
opDollar
;
opSlice
(size_t, DollarToken);
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)));
generate
(Fun)(Fun fun
)fun
);
generate
(alias fun)()fun
, создаётся диапазон, front которого определяется последовательными вызовами для fun
().
Особенно полезно вызывать функцию с глобальными побочными эффектами (случайными функциями), или для создания диапазонов, выраженных как единственный делегат, а не целый структура front/popFront/empty.
fun
может быть передана также параметром псевдонима шаблона (существующие функции, делегаты, структуры с заданным static opCall) или величиной времени выполнения (делегат, объект функции). Результирующий диапазон моделирует InputRange (входной диапазон, std.range.primitives.isInputRange).
Результирующий диапазон будет вызывать fun
() при конструировании, и каждом вызове
popFront, и при вызове front будет возвращаться кешированная величина.
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);
Cycle
ничего не меняет),
Cycle
обнаруживает это и выводит псевдоним исходного диапазона. Если исходный диапазон имеет произвольный доступ, Cycle
предоставляет произвольный доступ и также предлагает конструктор, принимающий индекс начальной позиции index. Cycle
работает со статическими массивами в дополнение к диапазонам, в основном из соображений производительности.
Замечание: Входной диапазон не должен быть пустым.
Совет: Это отличный способ реализации простых кольцевых буферов.
Переместиться к: 2
input
, size_t index
= 0);
Переместиться к: 2
front
();
front
();
front
(ElementType!R val
);
Переместиться к: 2
empty
;
Переместиться к: 2
popFront
();
Переместиться к: 2
opIndex
(size_t n
);
opIndex
(size_t n
);
opIndexAssign
(ElementType!R val
, size_t n
);
Переместиться к: 2
save
();
Переместиться к: 2
opDollar
;
Переместиться к: 2
opSlice
(size_t i
, size_t j
);
opSlice
(size_t i
, DollarToken);
Cycle
(R) if (isStaticArray!R);
cycle
(R)(R input
)cycle
(R)(R input
, size_t index
= 0)cycle
(R)(R input
)cycle
(R)(ref R input
, size_t index
= 0)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 ]));
input
, size_t index
= 0);
front
();
empty
;
popFront
();
opIndex
(size_t n
);
save
();
opDollar
;
opSlice
(size_t i
, size_t j
);
opSlice
(size_t i
, DollarToken);
Переместиться к: back · empty · front · length · moveAt · moveBack · moveFront · opDollar · opIndex · opIndexAssign · opSlice · popBack · popFront · save · this
Zip
(Ranges...) if (Ranges.length && allSatisfy!(isInputRange, Ranges));
zip
(Ranges...)(Ranges ranges
)zip
(Ranges...)(StoppingPolicy sp
, Ranges 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" ]);
rs
, StoppingPolicy s
= StoppingPolicy.shortest);
empty
;
true
, если диапазон дошел до конца. Тест зависит от политики остановки (stopping policy).save
();
front
(ElementType v
);
front
всех итерируемых диапазонов.moveFront
();
moveBack
();
back
(ElementType v
);
popFront
();
popBack
();
popBack
во всех контролируемых диапазонах.length
();
length
для диапазона. Определено, только если для всех диапазонов определён
length
.opDollar
= length;
opSlice
(size_t from
, size_t to
);
opIndex
(size_t n
);
n
-й элемент составного диапазона. Определено, только если для всех диапазонов определен произвольный доступ.opIndexAssign
(ElementType v
, size_t n
);
n
-й элемент составного диапазона. Определено, только если для всех диапазонов определен произвольный доступ.
n
-й элемент составного диапазона. Определено, только если для всех диапазонов определен произвольный доступ.moveAt
(size_t n
);
n
-й элемент составного диапазона. Определено, только если для всех диапазонов определен произвольный доступ.
n
-й элемент составного диапазона. Определено, только если для всех диапазонов определен произвольный доступ.Переместиться к: this
Lockstep
(Ranges...) if (Ranges.length > 1 && allSatisfy!(isInputRange, Ranges));
lockstep
(Ranges...)(Ranges ranges
)lockstep
(Ranges...)(Ranges ranges
, StoppingPolicy s
)Lockstep
выводит наружу псевдоним на него. Если у диапазонов различные длины и
s
== StoppingPolicy.shortest
, остановка происходит после того, как самый короткий диапазон станет пустым. Если у диапазонов различные длины и s
== StoppingPolicy.requireSameLength, бросается исключение. s
не может быть StoppingPolicy.longest, и его передача вызывает исключение.
Lockstep
в обратном порядке и с индексом возможны только тогда,
когда s
== StoppingPolicy.requireSameLength, чтобы сохранять индексы.
Если попытаться итерировать в обратном порядке при s
==
StoppingPolicy.shortest, будет брошено исключение.
По умолчанию, StoppingPolicy устанавливается в StoppingPolicy.shortest.
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); }
Recurrence
(alias fun, StateType, size_t stateSize);
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]));
Sequence
(alias fun, State);
sequence
(alias fun, State...)(State args
);
Sequence
(последовательность) похожа на Recurrence за исключением того, что эта итерация представлена в так называемой закрытой форме. Это означает, что n-ый элемент в серии вычисляется непосредственно из начальных величин и самого n. Это подразумевает, что интерфейс, предлагаемый Sequence
– диапазон с произвольным доступом, по сравнению с обычной Recurrence, которая предлагает только лидирующую итерацию.
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);
iota
(B, E, S)(B begin
, E end
, S step
)iota
(B, E)(B begin
, E end
)iota
(B, E)(B begin
, E end
)iota
(E)(E end
)iota
(E(0), end
))));
iota
(B, E, S)(B begin
, E end
, S step
)iota
(B, E)(B begin
, E end
)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
enforceNotJagged
assumeNotJagged
Переместиться к: back · empty · front · length · moveAt · moveBack · moveFront · opDollar · opIndex · opIndexAssign · opSlice · popBack · popFront · save · this
FrontTransversal
(Ror, TransverseOptions opt = TransverseOptions.assumeJagged);
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 ][]));
input
);
input
.empty
;
front
();
moveFront
();
popFront
();
save
();
back
();
popBack
();
moveBack
();
opIndex
(size_t n
);
moveAt
(size_t n
);
opIndexAssign
(ElementType val
, size_t n
);
length
();
opDollar
= length;
opSlice
(size_t lower
, size_t upper
);
Переместиться к: back · empty · front · length · moveAt · moveBack · moveFront · opDollar · opIndex · opIndexAssign · opSlice · popBack · popFront · save · this
Transversal
(Ror, TransverseOptions opt = TransverseOptions.assumeJagged);
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 ][]));
input
, size_t n
);
input
и индекса.empty
;
Переместиться к: 2
front
();
moveFront
();
front
(E val
);
popFront
();
save
();
Переместиться к: 2
back
();
popBack
();
moveBack
();
back
(E val
);
opIndex
(size_t n
);
moveAt
(size_t n
);
opIndexAssign
(E val
, size_t n
);
length
();
opDollar
= length;
opSlice
(size_t lower
, size_t upper
);
transposed
(RangeOfRanges)(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) { assert(array(e) == witness[i++]); }
Переместиться к: back · front · indices · length · moveAt · moveBack · moveFront · opIndex · opIndexAssign · opSlice · physicalIndex · popBack · popFront · save · source
Indexed
(Source,
Indices) if (isRandomAccessRange!Source && isInputRange!Indices
&& is(typeof(Source.init[ElementType!Indices.init])));
indexed
(Source, Indices)(Source source
, Indices indices
);
source
(источник) и indices
(индексы), и создаёт видимость источника, как будто его элементы были переупорядочены в соответсвии с 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
front
();
popFront
();
save
();
front
(ElementType!Source newVal
);
moveFront
();
Переместиться к: 2
back
();
popBack
();
back
(ElementType!Source newVal
);
moveBack
();
length
();
opIndex
(size_t index
);
opSlice
(size_t a
, size_t b
);
opIndexAssign
(ElementType!Source newVal
, size_t index
);
moveAt
(size_t index
);
source
();
source
.indices
();
indices
.physicalIndex
(size_t logicalIndex
);
auto ind = indexed([1, 2, 3, 4, 5], [1, 3, 4]); assert(ind.physicalIndex(0) == 1);
chunkSize
исходного диапазона
source
. Исходный диапазон должен быть лидируюшим диапазоном. chunkSize
должен быть больше нуля.
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))));
source
, size_t chunkSize
);
front
();
popFront
();
empty
();
save
();
length
();
opIndex
(size_t index
);
opSlice
(size_t lower
, size_t upper
);
back
();
popBack
();
source
на chunkCount
кусков приблизительно равной длины. Источник должен быть лидирующим диапазоном с известной длиной.
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]);
source
, size_t chunkCount
);
front
();
popFront
();
empty
();
save
();
length
();
opIndex
(size_t index
);
opSlice
(size_t lower
, size_t upper
);
back
();
popBack
();
only
(Values...)(auto ref Values values
)values
в диапазоне, который содержит в себе все свои элементы на месте.
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"));
enumerate
(Enumerator = size_t, Range)(Range range
, Enumerator start
= 0)range
с прилагаемой индексной переменной.
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]);
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
SearchPolicy
: int;
linear
trot
gallop
binarySearch
binarySearch
используется как последний шаг в стратегиях trot, gallop, trotBackwards, and gallopBackwards.trotBackwards
gallopBackwards
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)); // проходит, хотя не должно
empty
();
save
();
front
();
popFront
();
back
();
popBack
();
opIndex
(size_t i
);
opSlice
(size_t a
, size_t b
);
length
();
opDollar
= length;
release
();
lowerBound
(SearchPolicy sp = SearchPolicy.binarySearch, V)(V value
)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 ]));
upperBound
(SearchPolicy sp = SearchPolicy.binarySearch, V)(V value
)value
, x) – истина для всех x
(например, если pred – это "меньше, чем", возвращает часть диапазона с элементами, которые строго больше, чем value
). План поиска и его сложность описаны в SearchPolicy.
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]));
equalRange
(V)(V value
)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 ]));
trisect
(V)(V value
)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 ]));
contains
(V)(V value
)true
тогда и только тогда, когда value
можно найти в диапазоне, который считается отсортированным. Выполняется за Ο(log(r.length))
вычислений pred. Смотрите также binary_search в STL.groupBy
()();
assumeSorted
(alias pred = "a < b", R)(R 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
RefRange
(R) if (isInputRange!R);
refRange
(R)(R* range
)refRange
(R)(R* range
)range
, и RefRange
всегда будут иметь одни и те же элементы. Любое действие, выполненное с одним, влияет на другое. 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 |
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");
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);
range
);
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
.opAssign
(typeof(null) rhs
);
ptr
();
front
();
front
();
front
(ElementType!R value
);
empty
();
empty
();
popFront
();
save
();
save
();
Переместиться к: 2
opSlice
();
opSlice
();
back
();
back
();
back
(ElementType!R value
);
popBack
();
opIndex
(IndexType)(IndexType index
);
opIndex
(IndexType)(IndexType index
);
moveFront
();
moveBack
();
moveAt
(size_t index
);
length
();
length
();
opDollar
= length;
opSlice
(IndexType1, IndexType2)(IndexType1 begin
, IndexType2 end
);
opSlice
(IndexType1, IndexType2)(IndexType1 begin
, IndexType2 end
);
NullSink
;
import std.algorithm.iteration : map; import std.algorithm.mutation : copy; [4, 5, 6].map!(x => x * 2).copy(NullSink()); // данные удаляются
tee
(Flag!"pipeOnPop" pipeOnPop = Yes.pipeOnPop, R1, R2)(R1 inputRange
, R2 outputRange
)tee
(alias fun, Flag!"pipeOnPop" pipeOnPop = Yes.pipeOnPop, R1)(R1 inputRange
)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);
padLeft
(R, E)(R r
, E e
, size_t n
)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 |
длина, до которой заполнить |
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"));
padRight
(R, E)(R r
, E e
, size_t n
)r
, заполняя конец диапазона элементом e
. Элемент e
должен быть общего типа с типом элементов диапазона r
, как определено std.traits.CommonType.
Если n
меньше, чем длина r
, тогда r
возвращается немодифицированным.
r
.
Исключением являются функции back и popBack, которые также требуют, чтобы диапазон имел длину вдобавок к back и popBack.
R r |
входной диапазон с длиной |
E e |
элемент, который должен заполнить диапазон |
size_t n |
длина, до которой заполнить |
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___"));