Spec-Zone.ru › D

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_backward STL:
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 пуст.
См. также:
uninitializedFill initializeAll
Примеры:
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 Диапазон ввода, предоставляющий ссылки на элементы и имеющий присваиваемые элементы
См. также:
fill uninitializeFill
Примеры:
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 Присваивается каждому элементу диапазона
См. также:
fill initializeAll
Примеры:
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

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API