std.algorithm.mutation
Это подмодуль std.algorithm. Он содержит общие алгоритмы мутации.
| Имя функции | Описание |
|---|---|
bringToFront | Если a = [1, 2, 3] и b = [4, 5, 6, 7], то bringToFront(a, b) оставляет a = [4, 5, 6] и b = [7, 1, 2, 3]. |
copy | Копирует диапазон в другой. Если a = [1, 2, 3] и b = new int[5], то copy(a, b) оставляет b = [1, 2, 3, 0, 0] и возвращает b[3 .. $]. |
fill | Заполняет диапазон шаблоном. Например, если a = new int[3], то fill(a, 4) оставляет a = [4, 4, 4] и fill(a, [3, 4]) оставляет a = [3, 4, 3]. |
initializeAll | Если a = [1.2, 3.4], то initializeAll(a) оставляет a = [double.init, double.init]. |
move | move(a, b) перемещает a в b. move(a) считывает a деструктивно при необходимости. |
moveEmplace | Аналогично move, но предполагает, что target не инициализировано. |
moveAll | Перемещает все элементы из одного диапазона в другой. |
moveEmplaceAll | Аналогично moveAll, но предполагает, что все элементы в target не инициализированы. |
moveSome | Перемещает как можно больше элементов из одного диапазона в другой. |
moveEmplaceSome | Аналогично moveSome, но предполагает, что все элементы в target не инициализированы. |
remove | Удаляет элементы из диапазона на месте и возвращает укороченный диапазон. |
reverse | Если a = [1, 2, 3], то reverse(a) изменяет его на [3, 2, 1]. |
strip | Удаляет все ведущие и хвостовые элементы, равные значению или удовлетворяющие предикату. Если a = [1, 1, 0, 1, 1], то strip(a, 1) и strip!(e => e == 1)(a) возвращают [0]. |
stripLeft | Удаляет все ведущие элементы, равные значению или удовлетворяющие предикату. Если a = [1, 1, 0, 1, 1], то stripLeft(a, 1) и stripLeft!(e => e == 1)(a) возвращает [0, 1, 1]. |
stripRight | Удаляет все хвостовые элементы, равные значению или удовлетворяющие предикату. Если a = [1, 1, 0, 1, 1], то stripRight(a, 1) и stripRight!(e => e == 1)(a) возвращает [1, 1, 0]. |
swap | Меняет местами два значения. |
swapAt | Меняет местами два значения по индексам. |
swapRanges | Меняет местами все элементы двух диапазонов. |
uninitializedFill | Заполняет диапазон (предполагается неинициализированный) значением. |
- Лицензия:
- Boost License 1.0.
- Авторы:
- Андрей Александреску
- Исходный код
- std/algorithm/mutation.d
- size_t bringToFront(InputRange, ForwardRange)(InputRange front, ForwardRange back)
Constraints: if (isInputRange!InputRange && isForwardRange!ForwardRange); -
bringToFrontпринимает два диапазонаfrontиback, которые могут быть разных типов. Рассматривая конкатенациюfrontиbackкак один объединённый диапазон,bringToFrontвращает этот объединённый диапазон таким образом, чтобы все элементы изbackбыли перемещены в начало объединённого диапазона. Относительный порядок элементов вfrontиback, соответственно, остаётся неизменным.Функция
bringToFrontобрабатывает строки на уровне кодовых единиц и не заботится об целостности кода Юникода.bringToFrontразработана как функция для перемещения элементов в диапазонах, а не как функция для работы со строками.
Выполняет Ο(max(front.length, back.length)) вычисленийswap.
ФункцияbringToFrontможет вращать элементы в одном буфере влево или вправо, обменивать буферы равной длины и даже перемещать элементы между непересекающимися буферами различных типов и разной длины.- Предварительные условия
- Либо
frontиbackне пересекаются, либоbackдостижимо изfrontиfrontне достижимо изback.
- Параметры:
InputRange frontдиапазон ввода ForwardRange backдиапазон прямого доступа
- Возвращаемое значение:
- Количество элементов, перемещённых вперёд, т.е. длина
back.
- См. также:
rotateв STL
- Примеры:
- Самое простое применение
bringToFront- это вращение элементов в буфере. Например:auto arr = [4, 5, 6, 7, 1, 2, 3]; auto p = bringToFront(arr[0 .. 4], arr[4 .. $]); writeln(p); // arr.length - 4 writeln(arr); // [1, 2, 3, 4, 5, 6, 7]
- Примеры:
- Диапазон
frontможет фактически «перешагнуть» через диапазонback. Это очень полезно с диапазонами прямого доступа, которые не могут удобно вычислять правые ограниченные поддиапазоны, какarr[0 .. 4]выше. В примере ниже,r2является правым поддиапазономr1.import std.algorithm.comparison : equal; import std.container : SList; import std.range.primitives : popFrontN; auto list = SList!(int)(4, 5, 6, 7, 1, 2, 3); auto r1 = list[]; auto r2 = list[]; popFrontN(r2, 4); assert(equal(r2, [ 1, 2, 3 ])); bringToFront(r1, r2); assert(equal(list[], [ 1, 2, 3, 4, 5, 6, 7 ]));
- Примеры:
- Элементы могут быть обменены между диапазонами разных типов:
import std.algorithm.comparison : equal; import std.container : SList; auto list = SList!(int)(4, 5, 6, 7); auto vec = [ 1, 2, 3 ]; bringToFront(list[], vec); assert(equal(list[], [ 1, 2, 3, 4 ])); assert(equal(vec, [ 5, 6, 7 ]));
- Примеры:
- Целостность Юникода не сохраняется:
import std.string : representation; auto ar = representation("a".dup); auto br = representation("ç".dup); bringToFront(ar, br); auto a = cast(char[]) ar; auto b = cast(char[]) br; // Illegal UTF-8 writeln(a); // "\303" // Illegal UTF-8 writeln(b); // "\247a"
- TargetRange copy(SourceRange, TargetRange)(SourceRange source, TargetRange target)
Constraints: if (isInputRange!SourceRange && isOutputRange!(TargetRange, ElementType!SourceRange)); -
Копирует содержимое
sourceвtargetи возвращает оставшуюся (не заполненную) частьtarget.- Предварительные условия
-
targetдолжен иметь достаточно места для размещения всего содержимогоsource.
- Параметры:
SourceRange sourceдиапазон ввода TargetRange targetдиапазон вывода
- Возвращаемое значение:
- Не заполненная часть target
- Примеры:
-
int[] a = [ 1, 5 ]; int[] b = [ 9, 8 ]; int[] buf = new int[](a.length + b.length + 10); auto rem = a.copy(buf); // copy a into buf rem = b.copy(rem); // copy b into remainder of buf writeln(buf[0 .. a.length + b.length]); // [1, 5, 9, 8] assert(rem.length == 10); // unused slots in buf
- Примеры:
- Пока элементы целевого диапазона поддерживают присваивание из элементов исходного диапазона, принимаются разные типы диапазонов:
float[] src = [ 1.0f, 5 ]; double[] dest = new double[src.length]; src.copy(dest);
- Примеры:
- Для копирования не более
nэлементов из диапазона, вы можете использоватьstd.range.take:import std.range; int[] src = [ 1, 5, 8, 9, 10 ]; auto dest = new int[](3); src.take(dest.length).copy(dest); writeln(dest); // [1, 5, 8]
- Примеры:
- Для копирования только тех элементов из диапазона, которые удовлетворяют предикату, используйте
filter:import std.algorithm.iteration : filter; int[] src = [ 1, 5, 8, 9, 10, 1, 2, 0 ]; auto dest = new int[src.length]; auto rem = src .filter!(a => (a & 1) == 1) .copy(dest); writeln(dest[0 .. $ - rem.length]); // [1, 5, 9, 1]
- Примеры:
-
std.range.retroможет использоваться для достижения поведения, аналогичногоcopy_backwardSTL:import std.algorithm, std.range; int[] src = [1, 2, 4]; int[] dest = [0, 0, 0, 0, 0]; src.retro.copy(dest.retro); writeln(dest); // [0, 0, 1, 2, 4]
- void fill(Range, Value)(auto ref Range range, auto ref Value value)
Constraints: if (isInputRange!Range && is(typeof(range.front = value)) || isSomeChar!Value && is(typeof(range[] = value)));
void fill(InputRange, ForwardRange)(InputRange range, ForwardRange filler)
Constraints: if (isInputRange!InputRange && (isForwardRange!ForwardRange || isInputRange!ForwardRange && isInfinite!ForwardRange) && is(typeof(InputRange.init.front = ForwardRange.init.front))); -
Присваивает
valueкаждому элементу входного диапазонаrange.В качестве альтернативы, вместо использования одного
valueдля заполненияrange, может быть предоставленfilterдиапазон прямого доступа. Длинаfillerиrangeне обязательно должны совпадать, ноfillerне должен быть пустым.- Параметры:
Range rangeДиапазон ввода, предоставляющий ссылки на элементы и имеющий присваиваемые элементы Value valueПрисваивается каждому элементу диапазона ForwardRange fillerДиапазон прямого доступа, представляющий шаблон заполнения.
- Исключения:
- Если
fillerпуст.
- См. также:
-
uninitializedFillinitializeAll
- Примеры:
-
int[] a = [ 1, 2, 3, 4 ]; fill(a, 5); writeln(a); // [5, 5, 5, 5]
- Примеры:
-
int[] a = [ 1, 2, 3, 4, 5 ]; int[] b = [ 8, 9 ]; fill(a, b); writeln(a); // [8, 9, 8, 9, 8]
- void initializeAll(Range)(Range range)
Constraints: if (isInputRange!Range && hasLvalueElements!Range && hasAssignableElements!Range);
void initializeAll(Range)(Range range)
Constraints: if (is(Range == char[]) || is(Range == wchar[])); -
Инициализирует все элементы
rangeих.initзначением. Предполагает, что элементы диапазона не инициализированы.- Параметры:
Range rangeДиапазон ввода, предоставляющий ссылки на элементы и имеющий присваиваемые элементы
- См. также:
-
filluninitializeFill
- Примеры:
-
import core.stdc.stdlib : malloc, free; struct S { int a = 10; } auto s = (cast(S*) malloc(5 * S.sizeof))[0 .. 5]; initializeAll(s); writeln(s); // [S(10), S(10), S(10), S(10), S(10)] scope(exit) free(s.ptr);
- void move(T)(ref T source, ref T target);
T move(T)(return ref scope T source); -
Перемещает
sourceвtarget, используя деструктивное копирование при необходимости.Если
Tявляется структурой с определённым деструктором или postblit, source сбрасывается до своего.initзначения после перемещения в target, в противном случае он остаётся неизменным.- Предварительные условия
- Если source имеет внутренние указатели, которые указывают на себя и не определяет opPostMove, он не может быть перемещён и вызовет ошибку проверки.
- Параметры:
T sourceДанные для копирования. T targetМесто для копирования. Деструктор, если он есть, вызывается до выполнения копирования.
- Примеры:
- Для типов, не являющихся структурами,
moveпросто выполняетtarget = source:Object obj1 = new Object; Object obj2 = obj1; Object obj3; move(obj2, obj3); assert(obj3 is obj1); // obj2 unchanged assert(obj2 is obj1);
- Примеры:
-
// Structs without destructors are simply copied struct S1 { int a = 1; int b = 2; } S1 s11 = { 10, 11 }; S1 s12; move(s11, s12); writeln(s12); // S1(10, 11) writeln(s11); // s12 // But structs with destructors or postblits are reset to their .init value // after copying to the target. struct S2 { int a = 1; int b = 2; ~this() pure nothrow @safe @nogc { } } S2 s21 = { 3, 4 }; S2 s22; move(s21, s22); writeln(s21); // S2(1, 2) writeln(s22); // S2(3, 4)
- Примеры:
- Некопируемые структуры всё равно могут быть перемещены:
struct S { int a = 1; @disable this(this); ~this() pure nothrow @safe @nogc {} } S s1; s1.a = 2; S s2 = move(s1); writeln(s1.a); // 1 writeln(s2.a); // 2
- Примеры:
-
opPostMoveбудет вызван, если определён:struct S { int a; void opPostMove(const ref S old) { writeln(a); // old.a a++; } } S s1; s1.a = 41; S s2 = move(s1); writeln(s2.a); // 42
- pure @system void moveEmplace(T)(ref T source, ref T target);
-
Аналогично
move, но предполагает, чтоtargetне инициализирован. Это более эффективно, потому чтоsourceможет быть скопирован вtargetбез предварительного разрушения или инициализации.- Параметры:
T sourceзначение, которое нужно переместить в target T targetнеинициализированное значение, которое заполняется source
- Примеры:
-
static struct Foo { pure nothrow @nogc: this(int* ptr) { _ptr = ptr; } ~this() { if (_ptr) ++*_ptr; } int* _ptr; } int val; Foo foo1 = void; // uninitialized auto foo2 = Foo(&val); // initialized assert(foo2._ptr is &val); // Using `move(foo2, foo1)` would have an undefined effect because it would destroy // the uninitialized foo1. // moveEmplace directly overwrites foo1 without destroying or initializing it first. moveEmplace(foo2, foo1); assert(foo1._ptr is &val); assert(foo2._ptr is null); writeln(val); // 0
- InputRange2 moveAll(InputRange1, InputRange2)(InputRange1 src, InputRange2 tgt)
Constraints: if (isInputRange!InputRange1 && isInputRange!InputRange2 && is(typeof(move(src.front, tgt.front)))); -
Вызывает
move(a, b)для каждого элементаaвsrcи соответствующего элементаbвtgt, в порядке возрастания.- Предварительные условия
-
walkLength(src) <= walkLength(tgt). Это предварительное условие будет проверено. Если вы не можете гарантировать, что вtgtдостаточно места для размещения всех элементовsrc, используйтеmoveSomeвместо этого.
- Параметры:
InputRange1 srcДиапазон ввода с перемещаемыми элементами. InputRange2 tgtДиапазон ввода с элементами, в которые можно переместить элементы из src
- Возвращаемое значение:
- Остаток
tgtпосле перемещения всех элементов изsrc.
- Примеры:
-
int[3] a = [ 1, 2, 3 ]; int[5] b; assert(moveAll(a[], b[]) is b[3 .. $]); writeln(a[]); // b[0 .. 3] int[3] cmp = [ 1, 2, 3 ]; writeln(a[]); // cmp[]
- @system InputRange2 moveEmplaceAll(InputRange1, InputRange2)(InputRange1 src, InputRange2 tgt)
Constraints: if (isInputRange!InputRange1 && isInputRange!InputRange2 && is(typeof(moveEmplace(src.front, tgt.front))));
-
Аналогично
moveAll, но предполагает, что все элементы вtgtне инициализированы. ИспользуетmoveEmplaceдля перемещения элементов изsrcповерх элементов изtgt.- Примеры:
-
static struct Foo { ~this() pure nothrow @nogc { if (_ptr) ++*_ptr; } int* _ptr; } int[3] refs = [0, 1, 2]; Foo[3] src = [Foo(&refs[0]), Foo(&refs[1]), Foo(&refs[2])]; Foo[5] dst = void; auto tail = moveEmplaceAll(src[], dst[]); // move 3 value from src over dst assert(tail.length == 2); // returns remaining uninitialized values initializeAll(tail); import std.algorithm.searching : all; assert(src[].all!(e => e._ptr is null)); assert(dst[0 .. 3].all!(e => e._ptr !is null));
- Tuple!(InputRange1, InputRange2) moveSome(InputRange1, InputRange2)(InputRange1 src, InputRange2 tgt)
Constraints: if (isInputRange!InputRange1 && isInputRange!InputRange2 && is(typeof(move(src.front, tgt.front)))); -
Вызывает
move(a, b)для каждого элементаaвsrcи соответствующего элементаbвtgt, в порядке возрастания, останавливаясь, когда какой-либо из диапазонов исчерпан.- Параметры:
InputRange1 srcДиапазон ввода input range с перемещаемыми элементами. InputRange2 tgtДиапазон ввода input range с элементами, в которые можно перемещать элементы из src.
- Возвращает:
- Остальные части двух диапазонов после исчерпания одного из них.
- Примеры:
-
int[5] a = [ 1, 2, 3, 4, 5 ]; int[3] b; assert(moveSome(a[], b[])[0] is a[3 .. $]); writeln(a[0 .. 3]); // b writeln(a); // [1, 2, 3, 4, 5]
- @system Tuple!(InputRange1, InputRange2) moveEmplaceSome(InputRange1, InputRange2)(InputRange1 src, InputRange2 tgt)
Constraints: if (isInputRange!InputRange1 && isInputRange!InputRange2 && is(typeof(move(src.front, tgt.front)))); -
То же, что и
moveSome, но предполагает, что все элементы вtgtне инициализированы. ИспользуетmoveEmplaceдля перемещения элементов изsrcповерх элементов изtgt.- Примеры:
-
static struct Foo { ~this() pure nothrow @nogc { if (_ptr) ++*_ptr; } int* _ptr; } int[4] refs = [0, 1, 2, 3]; Foo[4] src = [Foo(&refs[0]), Foo(&refs[1]), Foo(&refs[2]), Foo(&refs[3])]; Foo[3] dst = void; auto res = moveEmplaceSome(src[], dst[]); writeln(res.length); // 2 import std.algorithm.searching : all; assert(src[0 .. 3].all!(e => e._ptr is null)); assert(src[3]._ptr !is null); assert(dst[].all!(e => e._ptr !is null));
- enum SwapStrategy: int;
-
Определяет стратегию перестановки для алгоритмов, которым требуется переставлять элементы в диапазоне (например, разделение и сортировка). Стратегия касается перестановки элементов, которые не являются основным вопросом алгоритма. Например, рассмотрим алгоритм, который сортирует
[ "abc", "b", "aBc" ]поtoUpper(a) < toUpper(b). Этот алгоритм может выбрать перестановку двух эквивалентных строк"abc"и"aBc". Это не влияет на сортировку, так как как["abc", "aBc", "b" ]и[ "aBc", "abc", "b" ]являются допустимыми результатами.В некоторых ситуациях алгоритм не должен изменять относительный порядок эквивалентных элементов (в приведенном выше примере, только
[ "abc", "aBc", "b" ]будет правильным результатом). Такие алгоритмы называются стабильными. Если алгоритм сортировки может произвольно переставлять эквивалентные элементы, порядок называется нестабильным.
Еще один класс алгоритмов может выбрать промежуточную компромиссную позицию, являясь стабильным только для определенного поддиапазона диапазона. Для такого поведения нет общепринятой терминологии; эта библиотека называет его полустабильным.
В целом, стратегия упорядочиванияstableможет быть более затратной по времени и/или ресурсам, чем другие две, потому что она накладывает дополнительные ограничения. Аналогично,semistableможет быть дороже, чемunstable. Поскольку (полу-)стабильность не требуется очень часто, алгоритмы сортировки в этом модуле, параметризованныеSwapStrategy, все выбираютSwapStrategy.unstableв качестве значения по умолчанию.- Примеры:
-
int[] a = [0, 1, 2, 3]; writeln(remove!(SwapStrategy.stable)(a, 1)); // [0, 2, 3] a = [0, 1, 2, 3]; writeln(remove!(SwapStrategy.unstable)(a, 1)); // [0, 3, 2]
- Примеры:
-
import std.algorithm.sorting : partition; // Put stuff greater than 3 on the left auto arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; writeln(partition!(a => a > 3, SwapStrategy.stable)(arr)); // [1, 2, 3] writeln(arr); // [4, 5, 6, 7, 8, 9, 10, 1, 2, 3] arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; writeln(partition!(a => a > 3, SwapStrategy.semistable)(arr)); // [2, 3, 1] writeln(arr); // [4, 5, 6, 7, 8, 9, 10, 2, 3, 1] arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; writeln(partition!(a => a > 3, SwapStrategy.unstable)(arr)); // [3, 2, 1] writeln(arr); // [10, 9, 8, 4, 5, 6, 7, 3, 2, 1]
- unstable
-
Разрешает свободную перестановку элементов, пока вывод удовлетворяет требованиям алгоритма.
- semistable
-
При разделении диапазонов на две части сохраняется относительный порядок элементов только слева от точки разбиения.
- stable
-
Сохраняет относительный порядок элементов в максимально возможной степени, разрешенной требованиями алгоритма.
- Range remove(SwapStrategy s = SwapStrategy.stable, Range, Offset...)(Range range, Offset offset)
Constraints: if (Offset.length >= 1 && allSatisfy!(isValidIntegralTuple, Offset)); -
Удаляет элементы по заданным смещениям из
rangeи возвращает укороченный диапазон.Например, вот как удалить один элемент из массива:
string[] a = [ "a", "b", "c", "d" ]; a = a.remove(1); // remove element at offset 1 assert(a == [ "a", "c", "d"]);
Обратите внимание, чтоremoveне изменяет длину исходного диапазона напрямую; вместо этого он возвращает укороченный диапазон. Если его возвращаемое значение не присваивается исходному диапазону, исходный диапазон сохранит свою исходную длину, хотя его содержимое изменится:
int[] a = [ 3, 5, 7, 8 ]; assert(remove(a, 1) == [ 3, 7, 8 ]); assert(a == [ 3, 7, 8, 8 ]);
Элемент со смещением1был удален, а остальные элементы сдвинулись вверх, чтобы заполнить его место, однако, исходный массив остается той же длины. Это происходит потому, что все функции вstd.algorithmизменяют только содержимое, а не топологию. Значение8повторяется, потому что была вызванаmoveдля переупорядочивания элементов, а в случае с целыми числамиmoveпросто копирует источник в место назначения. Чтобы заменитьaэффектом удаления, просто присвойте срез, возвращаемыйremove, ему, как показано в первом примере.
Вremoveможно передавать несколько индексов. В этом случае все элементы по соответствующим индексам удаляются. Индексы должны быть переданы в порядке возрастания, иначе произойдет исключение.
int[] a = [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ]; assert(remove(a, 1, 3, 5) == [ 0, 2, 4, 6, 7, 8, 9, 10 ]);
(Обратите внимание, что все индексы относятся к слотам в исходном массиве, а не в массиве по мере его постепенного сокращения.)
Можно использовать кортежи из двух целочисленных смещений для удаления диапазона индексов:
int[] a = [ 3, 4, 5, 6, 7]; assert(remove(a, 1, tuple(1, 3), 9) == [ 3, 6, 7 ]);
Кортеж передает диапазон, закрытый слева и открытый справа (согласованно со встроенными срезами), напримерtuple(1, 3)означает индексы1и2, но не3.
Наконец, можно передавать любые комбинации целочисленных смещений и кортежей, составленных из двух целочисленных смещений:
int[] a = [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ]; assert(remove(a, 1, tuple(3, 5), 9) == [ 0, 2, 5, 6, 7, 8, 10 ]);
В этом случае слоты в позициях 1, 3, 4 и 9 удаляются из массива.
Если необходимо удалить некоторые элементы в диапазоне, но порядок оставшихся элементов не должен сохраняться, вы можете передатьSwapStrategy.unstableвremove.
int[] a = [ 0, 1, 2, 3 ]; assert(remove!(SwapStrategy.unstable)(a, 1) == [ 0, 3, 2 ]);
В приведенном выше случае элемент в слоте1удаляется, но заменяется последним элементом диапазона. Используя снятие требования к стабильности,removeперемещает элементы с конца массива в освободившиеся слоты. Таким образом, выполняется меньше перемещений, что улучшает время выполнения функции.
Функцияremoveработает с двунаправленными диапазонами, имеющими присваиваемые элементы lvalue. Стратегия перемещения (в порядке от быстрой к медленной):
- Если
s == SwapStrategy.unstable && isRandomAccessRange!Range && hasLength!Range && hasLvalueElements!Range, то элементы перемещаются с конца диапазона в слоты, которые нужно заполнить. В этом случае выполняется минимальное количество перемещений. - В противном случае, если
s == SwapStrategy.unstable && isBidirectionalRange!Range && hasLength!Range && hasLvalueElements!Range, то элементы все еще перемещаются с конца диапазона, но тратится время на продвижение между слотами с помощью многократных вызововrange.popFront. - В противном случае элементы перемещаются постепенно к началу
range; данный элемент никогда не перемещается несколько раз, но перемещается больше элементов, чем в предыдущих случаях.
- Параметры:
s стратегия SwapStrategy, определяющая, нужно ли сохранять исходный порядок Range rangeдвунаправленный диапазон с членом длины Offset offsetкакой(ие) элемент(ы) удалить
- Возвращает:
- Диапазон, содержащий все элементы диапазона с удаленным смещением.
- Если
- Range remove(alias pred, SwapStrategy s = SwapStrategy.stable, Range)(Range range);
-
Уменьшает длину двунаправленного диапазона
range, удаляя элементы, которые удовлетворяютpred. Еслиs = SwapStrategy.unstable, элементы перемещаются с правого конца диапазона поверх элементов для удаления. Еслиs = SwapStrategy.stable(значение по умолчанию), элементы перемещаются постепенно к началу, так что их относительный порядок сохраняется. Возвращает отфильтрованный диапазон.- Параметры:
Range rangeдвунаправленный диапазон с элементами lvalue или изменяемыми массивами символов
- Возвращает:
- диапазон со всеми элементами, где
predявляетсяtrueудалёнными
- Примеры:
-
static immutable base = [1, 2, 3, 2, 4, 2, 5, 2]; int[] arr = base[].dup; // using a string-based predicate writeln(remove!("a == 2")(arr)); // [1, 3, 4, 5] // The original array contents have been modified, // so we need to reset it to its original state. // The length is unmodified however. arr[] = base[]; // using a lambda predicate writeln(remove!(a => a == 2)(arr)); // [1, 3, 4, 5]
- Range reverse(Range)(Range r)
Constraints: if (isBidirectionalRange!Range && (hasSwappableElements!Range || hasAssignableElements!Range && hasLength!Range && isRandomAccessRange!Range || isNarrowString!Range && isAssignable!(ElementType!Range)));
-
Инвертирует
rна месте. Выполняетr.length / 2вычисленийswap. Последовательности UTF, состоящие из нескольких кодовых единиц, сохраняются должным образом.- Параметры:
Диапазон rдвунаправленный диапазон bidirectional range с меняемыми элементами, диапазон с произвольным доступом с членом длины или узкая строка
- Возвращаемое значение:
-
r
- Примечание
- При передаче строки с модификаторами юникода в символах, таких как
\u0301, эта функция не будет правильно сохранять положение модификатора. Например, инвертированиеba\u0301d("bád") приведет к d\u0301ab ("d́ab") вместоda\u0301b("dáb").
- См. также:
-
std.range.retroдля ленивой инверсии без измененияr
- Примеры:
-
int[] arr = [ 1, 2, 3 ]; writeln(arr.reverse); // [3, 2, 1]
- Примеры:
-
char[] arr = "hello\U00010143\u0100\U00010143".dup; writeln(arr.reverse); // "\U00010143\u0100\U00010143olleh"
- Диапазон strip(Range, E)(Range range, E element)
Ограничения: если (isBidirectionalRange!Range && is(typeof(range.front == element) : bool));
Диапазон strip(alias pred, Range)(Range range)
Ограничения: если (isBidirectionalRange!Range && is(typeof(pred(range.back)) : bool));
Диапазон stripLeft(Range, E)(Range range, E element)
Ограничения: если (isInputRange!Range && is(typeof(range.front == element) : bool));
Диапазон stripLeft(alias pred, Range)(Range range)
Ограничения: если (isInputRange!Range && is(typeof(pred(range.front)) : bool));
Диапазон stripRight(Range, E)(Range range, E element)
Ограничения: если (isBidirectionalRange!Range && is(typeof(range.back == element) : bool));
Диапазон stripRight(alias pred, Range)(Range range)
Ограничения: если (isBidirectionalRange!Range && is(typeof(pred(range.back)) : bool)); -
Группа функций strip позволяет удалять ведущие, хвостовые или оба ведущих и хвостовые элементы.
Функция
stripLeftудалитfrontдиапазона, функцияstripRightудалитbackдиапазона, а функцияstripудалит какfront, так иbackдиапазона.
Обратите внимание, что функцииstripиstripRightтребуют, чтобы диапазон былBidirectionalRangeдиапазоном.
Все эти функции имеют два варианта: один принимает целевой элемент, где диапазон будет удаляться до тех пор, пока этот элемент не будет найден. Другой принимает лямбда-предикат, где диапазон будет удаляться до тех пор, пока предикат возвращает true.- Параметры:
Диапазон rangeдвунаправленный диапазон bidirectional range или диапазон input range E elementэлементы для удаления
- Возвращаемое значение:
- диапазон со всеми элементами диапазона, кроме элементов в начале и конце
- Примеры:
- Удаление ведущих и хвостовых элементов, равных целевому элементу.
writeln(" foobar ".strip(' ')); // "foobar" writeln("00223.444500".strip('0')); // "223.4445" writeln("ëëêéüŗōpéêëë".strip('ë')); // "êéüŗōpéê" writeln([1, 1, 0, 1, 1].strip(1)); // [0] writeln([0.0, 0.01, 0.01, 0.0].strip(0).length); // 2
- Примеры:
- Удаление ведущих и хвостовых элементов, пока предикат возвращает true.
writeln(" foobar ".strip!(a => a == ' ')()); // "foobar" writeln("00223.444500".strip!(a => a == '0')()); // "223.4445" writeln("ëëêéüŗōpéêëë".strip!(a => a == 'ë')()); // "êéüŗōpéê" writeln([1, 1, 0, 1, 1].strip!(a => a == 1)()); // [0] writeln([0.0, 0.01, 0.5, 0.6, 0.01, 0.0].strip!(a => a < 0.4)().length); // 2
- Примеры:
- Удаление ведущих элементов, равных целевому элементу.
writeln(" foobar ".stripLeft(' ')); // "foobar " writeln("00223.444500".stripLeft('0')); // "223.444500" writeln("ůůűniçodêéé".stripLeft('ů')); // "űniçodêéé" writeln([1, 1, 0, 1, 1].stripLeft(1)); // [0, 1, 1] writeln([0.0, 0.01, 0.01, 0.0].stripLeft(0).length); // 3
- Примеры:
- Удаление ведущих элементов, пока предикат возвращает true.
writeln(" foobar ".stripLeft!(a => a == ' ')()); // "foobar " writeln("00223.444500".stripLeft!(a => a == '0')()); // "223.444500" writeln("ůůűniçodêéé".stripLeft!(a => a == 'ů')()); // "űniçodêéé" writeln([1, 1, 0, 1, 1].stripLeft!(a => a == 1)()); // [0, 1, 1] writeln([0.0, 0.01, 0.10, 0.5, 0.6].stripLeft!(a => a < 0.4)().length); // 2
- Примеры:
- Удаление хвостовых элементов, равных целевому элементу.
writeln(" foobar ".stripRight(' ')); // " foobar" writeln("00223.444500".stripRight('0')); // "00223.4445" writeln("ùniçodêéé".stripRight('é')); // "ùniçodê" writeln([1, 1, 0, 1, 1].stripRight(1)); // [1, 1, 0] writeln([0.0, 0.01, 0.01, 0.0].stripRight(0).length); // 3
- Примеры:
- Удаление хвостовых элементов, пока предикат возвращает true.
writeln(" foobar ".stripRight!(a => a == ' ')()); // " foobar" writeln("00223.444500".stripRight!(a => a == '0')()); // "00223.4445" writeln("ùniçodêéé".stripRight!(a => a == 'é')()); // "ùniçodê" writeln([1, 1, 0, 1, 1].stripRight!(a => a == 1)()); // [1, 1, 0] writeln([0.0, 0.01, 0.10, 0.5, 0.6].stripRight!(a => a > 0.4)().length); // 3
- pure nothrow @nogc @trusted void swap(T)(ref T lhs, ref T rhs)
Ограничения: если (isBlitAssignable!T && !is(typeof(lhs.proxySwap(rhs))));
void swap(T)(ref T lhs, ref T rhs)
Ограничения: если (is(typeof(lhs.proxySwap(rhs)))); -
Меняет местами
lhsиrhs. Экземплярыlhsиrhsперемещаются в памяти, без вызоваopAssign, ни одной другой функции.Tне обязательно должны быть присваиваемыми, чтобы быть поменянными местами.Если
lhsиrhsссылаются на один и тот же экземпляр, то ничего не делается.
lhsиrhsдолжны быть изменяемыми. ЕслиTявляется структурой или объединением, то все его поля также должны быть (рекурсивно) изменяемыми.- Параметры:
T lhsДанные, которые должны быть поменяны местами с rhs.T rhsДанные, которые должны быть поменяны местами с lhs.
- Примеры:
-
// Swapping POD (plain old data) types: int a = 42, b = 34; swap(a, b); assert(a == 34 && b == 42); // Swapping structs with indirection: static struct S { int x; char c; int[] y; } S s1 = { 0, 'z', [ 1, 2 ] }; S s2 = { 42, 'a', [ 4, 6 ] }; swap(s1, s2); writeln(s1.x); // 42 writeln(s1.c); // 'a' writeln(s1.y); // [4, 6] writeln(s2.x); // 0 writeln(s2.c); // 'z' writeln(s2.y); // [1, 2] // Immutables cannot be swapped: immutable int imm1 = 1, imm2 = 2; static assert(!__traits(compiles, swap(imm1, imm2))); int c = imm1 + 0; int d = imm2 + 0; swap(c, d); writeln(c); // 2 writeln(d); // 1
- Примеры:
-
// Non-copyable types can still be swapped. static struct NoCopy { this(this) { assert(0); } int n; string s; } NoCopy nc1, nc2; nc1.n = 127; nc1.s = "abc"; nc2.n = 513; nc2.s = "uvwxyz"; swap(nc1, nc2); assert(nc1.n == 513 && nc1.s == "uvwxyz"); assert(nc2.n == 127 && nc2.s == "abc"); swap(nc1, nc1); swap(nc2, nc2); assert(nc1.n == 513 && nc1.s == "uvwxyz"); assert(nc2.n == 127 && nc2.s == "abc"); // Types containing non-copyable fields can also be swapped. static struct NoCopyHolder { NoCopy noCopy; } NoCopyHolder h1, h2; h1.noCopy.n = 31; h1.noCopy.s = "abc"; h2.noCopy.n = 65; h2.noCopy.s = null; swap(h1, h2); assert(h1.noCopy.n == 65 && h1.noCopy.s == null); assert(h2.noCopy.n == 31 && h2.noCopy.s == "abc"); swap(h1, h1); swap(h2, h2); assert(h1.noCopy.n == 65 && h1.noCopy.s == null); assert(h2.noCopy.n == 31 && h2.noCopy.s == "abc"); // Const types cannot be swapped. const NoCopy const1, const2; assert(const1.n == 0 && const2.n == 0); static assert(!__traits(compiles, swap(const1, const2)));
- void swapAt(R)(auto ref R r, size_t i1, size_t i2);
-
Меняет местами два элемента в диапазоне
r, указанных их индексамиi1иi2.- Параметры:
R rдиапазон со сменными элементами size_t i1первый индекс size_t i2второй индекс
- Примеры:
-
import std.algorithm.comparison : equal; auto a = [1, 2, 3]; a.swapAt(1, 2); assert(a.equal([1, 3, 2]));
- Tuple!(InputRange1, InputRange2) swapRanges(InputRange1, InputRange2)(InputRange1 r1, InputRange2 r2)
Ограничения: если (hasSwappableElements!InputRange1 && hasSwappableElements!InputRange2 && is(ElementType!InputRange1 == ElementType!InputRange2)); -
Меняет местами все элементы
r1с последующими элементами вr2. Возвращает кортеж, содержащий оставшиеся частиr1иr2, которые не были поменяны местами (один из них будет пустым). Диапазоны могут быть разных типов, но должны иметь одинаковый тип элементов и поддерживать обмен местами.- Параметры:
InputRange1 r1входной диапазон с меняемыми элементами InputRange2 r2входной диапазон с меняемыми элементами
- Возвращаемое значение:
- Кортеж, содержащий оставшиеся части r1 и r2, которые не были поменяны местами
- Примеры:
-
import std.range : empty; int[] a = [ 100, 101, 102, 103 ]; int[] b = [ 0, 1, 2, 3 ]; auto c = swapRanges(a[1 .. 3], b[2 .. 4]); assert(c[0].empty && c[1].empty); writeln(a); // [100, 2, 3, 103] writeln(b); // [0, 1, 101, 102]
- void uninitializedFill(Range, Value)(Range range, Value value)
Ограничения: если (isInputRange!Range && hasLvalueElements!Range && is(typeof(range.front = value))); -
Инициализирует каждый элемент
rangeзначениемvalue. Предполагается, что элементы диапазона не инициализированы. Это интересно для структур, которые определяют конструкторы копирования (для всех других типовfillи uninitializedFill эквивалентны).- Параметры:
Диапазон rangeвходной диапазон, предоставляющий ссылки на свои элементы и имеющий присваиваемые элементы Значение valueПрисваивается каждому элементу диапазона
- См. также:
-
fillinitializeAll
- Примеры:
-
import core.stdc.stdlib : malloc, free; auto s = (cast(int*) malloc(5 * int.sizeof))[0 .. 5]; uninitializedFill(s, 42); writeln(s); // [42, 42, 42, 42, 42] scope(exit) free(s.ptr);
© 1999–2021 The D Language Foundation
Licensed under the Boost License 1.0.
https://dlang.org/phobos/std_algorithm_mutation.html