Слово о iota и enumerate

Может быть Вы помните о том, с чего наш блог начинался… Вначале был уникальный язык программирования под названием Icon, которым мы увлекались некоторое время назад. Он пленил нас своей простотой и продуманностью, а также своей сверхвысокоуровневостью и необычной концепцией генераторов. Чуть позже мы познакомились с D, который пошел гораздо дальше, воплотив в жизнь концепцию диапазонов.

Именно о некоторых интересных алгоритмах над диапазонами (в основном, над числовыми) сегодня и поговорим.

Представьте, Вы оперируете непрерывным множеством чисел от какого-то минимального и какого-то максимального, и Вам нужно что-то сделать с каждым из элементов такого множества…
Первая идея, которая приходит Вам в голову будет выглядеть примерно так:
for (int i = minimum; i < maximum; i++)
{
 // некоторое действие
}

где minimum — начало диапазона чисел, maximum — его конец (и строго говоря, необязательно, чтобы тип переменной был int, но надеюсь идею вы поймете). Однако, в стандартной библиотеке D есть интересный алгоритм iota (в модуле std.range), который принимает в качестве аргументов от двух до трех параметров: начальный элемент, конечный элемент и необязательный параметр, который задает шаг:

auto r = iota(0.0, 0.5, 0.1);

Этот пример показывает создание числового диапазона от 0.0 до 0.5 (не включая) с шагом в 0.1, и в некоторых приложениях, в сочетании с таким интересными шаблонами как map и each из стандартной библиотеки может стать одной из любопытных замен для стандартных циклов.

Тут, как говориться, главное не переусердствовать — нужно быть предельно аккуратным, чтобы использование таких приемов не испортило код.

Другим интересным алгоритмом является алгоритм enumerate, который использует такую классную идею D, как кортежи типов.

Что делает enumerate?

Все очень просто: enumerate принимает некоторый диапазон (необязательно, числовой, кстати) и некоторое число (необязательный параметр), начиная с которого алгоритма начнет нумеровать элементы входного диапазона:

auto r = [0, 2, 4, 6, 8];
auto t = r.enumerate(0);

foreach (pair; t)
{
   writeln(pair[0], " ", pair[1]);
}

Данный пример выведет набор пар t в виде «номер элемент_массива_r«, т.е. по сути дела, создаст список пар индекс-значения, и отсчет будет начат с нуля. Весь фокус тут заключается в том, что enumerate генерирует список пар, который является одним элементом, состоящим из разных типов (такая штука называется кортежем типов). Кортеж типов, в данном случае, состоит из двух элементов — номера и элемента входного диапазона, и соответственно, к элементам кортежа можно обратиться по индексам 0 и 1.

Не поверите, насколько творчески можно использовать эти простые алгоритмы, главное применить смекалку и изобретательность!

P.S.: Вот вам пример. Жаль только без кода…

Однажды в интерфейсе одной программы необходимо было задать значения для QComboBox, которые были статичны и имелись в простом массиве строк. Цикл для этого не был пригоден, так как кода было уже много и наличие даже небольшого цикла в интерфейсной части могло бы сбить с толку. После недолгих раздумий была сделана нумерация массива строк с помощью enumerate, а добавление в QComboBox реализовано через each. В итоге, 2 строки кода и это прекрасно читается…

Добавить комментарий