В этой статье мы покажем ряд полезных фрагментов кода, которые известны практически каждому программисту на D. Здесь не будет каких-то интересных трюков и неожиданных решений, лишь скромная доля маленьких рецептов, которые способны упростить работу и которые иногда забываются.
Полная очистка динамического массива
Иногда требуется полностью опустошить динамический массив и для массива T[] это можно сделать следующим образом:
T[] a; a.length = 0;
Привести статический массив (массив с фиксированным размером) к динамическому массиву
Для массива T[n] (где n – это количество элементов в массиве) подобное приведение выполняется следующим образом:
T[n] a; T[] b = a[];
Получить изменяемую копию массива
Для неизменяемого (immutable) массива T[] это можно сделать так:
immutable(T[]) a; T[] b = a.dup;
Похожим образом выполняется обратный переход, но используется свойство .idup
. Вообще, это выполняется не только для массивов, но и для остальных типов данных, у которых определены .dup
и .idup
, при необходимости эти свойства добавляются вручную созданием либо функций с именами dup/idup, либо соответствующих методов.
Использование индекса в цикле foreach для алгоритмов, принимающих диапазоны
Практически каждому программисту на D знакома вот такая форма для цикла foreach:
foreach (i, e; array) { // operations }
где i – переменная, в которую попадает автоматически рассчитанный индекс элемента; e – сам элемент некой последовательности; array – некий массив элементов.
Это удобно и очень просто, но если вместо массива используется диапазон, особенно если его предварительно прогнали через целую цепочку алгоритмов, то работать это не будет. Однако, если импортировать enumerate
из std.range
и немного дополнить цикл foreach, то такая конструкция будет работать:
import std.range : enumerate; foreach (i, e; range.enumerate) { // operations }
где range – это диапазон для обработки.
Вот любопытный пример этой “идиомы” для получения изображения фурье-образа тестового сигнала, использующий нашу библиотеку ppmformats:
import std.stdio; auto fastAbs(float x) @system { uint p = *(cast(uint*) &x); p &=0x7fffffff; return *(cast(float*) &p); } auto renormalize(Range)(Range r) { import std.algorithm; auto maximalAbsoluteValue = r .map!(a => fastAbs(a)) .fold!max; return r .map!(a => a / maximalAbsoluteValue); } void main() { import std.algorithm; import std.complex; import std.math; import std.numeric; import std.random; import std.range; import ppmformats; auto rng = Random(unpredictableSeed); auto signalWithNoise(float x) { return (3.3 * sin(x)) + uniform(-0.3, 0.3, rng); } auto signal = iota(0, 2_048) .map!signalWithNoise; auto normalizedFFT(Range)(Range r) { return r .fft .map!(a => 20.0f * log10(abs(a ^^ 2))) .renormalize; } auto pd = signal .slide(1_024) .map!(a => normalizedFFT(a)); auto img = new P6Image(1024, 1024); foreach (i, e; pd.enumerate) { foreach (j, s; e.enumerate) { img[i, j] = new RGBColor( cast(int) (0.8 * 255.0 * abs(s)), 0, 255 - cast(int) (255 * abs(s)) ); } } img.save(`fft.ppm`); }
Результат предлагаем оценить самостоятельно.