В этой статье мы покажем ряд полезных фрагментов кода, которые известны практически каждому программисту на 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`);
}Результат предлагаем оценить самостоятельно.