Это перевод статьи «Associative arrays», опубликованной 1 января 2016 года. На мой вкус статья несколько излишне поверхностна и не содержит большого количества подробностей, но она может быть полезной тем, кто знаком с ассоциативными массивами в других языках программирования.

В языке D есть встроенная поддержка ассоциативных массивов, также известных как хэш-таблицы.
Они аналогичны Map в Java или std::unordered_map в C++.

Объявление ассоциативного массива



Чтобы объявить ассоциативный массив, используйте следующий синтаксис:

// Прим. перев.: value — тип значения, key — тип ключа
value[key] myAssociativeArray;



Вставка элементов в ассоциативный массив


Для вставки элементов в ассоциативный массив используйте оператор [].
Ниже приведён пример создания ассоциативного массива квадратов целых чисел от 0 до 10 и вывода их на экран.

import std.stdio;

void main()
{
    int[int] squares; // Объявление

    for (int i = 0; i <= 10; ++i)
        squares[i] = i * i; // Вставка в ассоциативный массив

    writeln(squares);
}


Запустив пример, мы получим следующий вывод:
[0:0, 6:36, 7:49, 2:4, 3:9, 10:100, 1:1, 8:64, 5:25, 4:16, 9:81]
Обратите внимание, что числа не отсортированы — это ожидаемо: ассоциативные массивы внутренне не сортируются.
Примечания:
  • Переназначение существующего ключа заменит значение.
  • Попытка обратиться к несуществующему ключу приведёт к ошибке core.exception.RangeError.


Удаление элементов из ассоциативного массива


Для удаления элементов из ассоциативного массива используйте функцию remove().

aa.remove("hello");


Проверка на существование ключа


Для проверки ключа на существование используйте оператор in, который возвращает указатель на значение. Если ключ не существует, указатель будет null.

int[int] squares;

// ...

int* p = 10 in squares;
// Прим. перев.: Не проверяйте на null операторами сравнения, используйте is
if (p !is null)
    writeln(*p);
else
    writeln("Нет значения.");


Очистка ассоциативного массива


Существует два способа очистить ассоциативный массив:
  1. Пройтись по ключам и удалить их
  2. Отбросить старый массив и создать новый


Способ 1: удаляем ключи


foreach (key; aa.keys)
    aa.remove(key);


Способ 2: создаём новый массив


Чтобы выбросить существующий массив, присвойте ему значение null.

aa = null; // помечено для сборки мусора
aa[1] = 1; // записано по новому адресу в памяти


Свойства


Мы уже знакомы с некоторыми свойствами ассоциативных массивов, например, remove() или keys. Ниже приведены остальные:
Свойство Описание
.sizeof Возвращает размер ссылки на ассоциативный массив. В 32-битных сборках это 4, а в 64-битных сборках 8.
.length Возвращает количество значений в массиве. В отличие от динамических массивов, это свойство только для чтения.
.dup Создаёт ассоциативный массив того же размера и копирует в него содержимое первого массива.
.keys Возвращает динамический массив, элементы которого являются ключами исходного ассоциативного массива.
.values Возвращает динамический массив, элементы которого являются значениями исходного ассоциативного массива.
.rehash На месте реорганизует массив, оптимизируя поиск по нему. rehash полезен, например, когда в программу подгружается таблица символов, по которой впоследствии нужно производить поиск. Возвращает ссылку на реорганизованный массив.
.byKey() Возвращает диапазон, подходящий для перебора с помощью цикла foreach ключей ассоциативного массива.
.byValue() Возвращает диапазон, подходящий для перебора с помощью цикла foreach значений ассоциативного массива.
.byKeyValue() Возвращает диапазон, подходящий для перебора с помощью цикла foreach пар ключ-значение ассоциативного массива. Возвращаемые пары представляются в виде непрозрачного типа со свойствами .key и .value, позволяющими обращаться соответственно к ключу и значению пары.
.get(Key key, lazy Value defVal) Ищет ключ key. Если он существует, возвращает соответствующее ему значение; если не существует, отрабатывает и возвращает значение по умолчанию defVal.


Что ещё почитать


Для более подробной информации (например, чтобы узнать о работе с классами и структурами в ассоциативных массивах) обратитесь к официальной документации на dlang.org.

Комментарии (6)


  1. ReklatsMasters
    09.01.2016 12:34

    Когда я писал парсер торрент-файлов на D, выяснилось, что ключи ассоциативных массивов располагаются в памяти не порядку. Это чертовски мешает, пришлось написать костыль.


    1. 9mm
      09.01.2016 13:30
      +1

      в статье об этом, как раз, написано. Если нужно поддержание отношения '<', то нужно, по старинке, использовать RedBlackTree из std.containers.


  1. AxisPod
    09.01.2016 12:50

    Если это hash map, то он внутри еще как сортируется, но сортируется он сначала по корзинам, в какую попадет значение, а потом внутри, уже по своей внутренней логике. Несортируемые это когда порядок не меняется, а здесь опять же он меняется.


  1. 1vanK
    09.01.2016 13:59

    Хеш-таблица должна внутренне упорядочиваться, иначе обращение к нужному элементу будет непозволительно долгим


  1. merhalak
    09.01.2016 15:52

    Проверка на существование ключа может ли быть такой:

    int[int] squares;
    ...
    int value = 10
    if (value in squares) 
        writeln(squares.get(value)); 
    else 
        writeln("Нет значения.");
    

    Или оно не скомпилируется/чем-либо хуже?


    1. 9mm
      09.01.2016 17:49
      +1

      хуже только тем, что поиск значения будет произведён дважды — один раз оператором 'in', затем методом 'get'. А так скомпилируется, чё.

      лучше уж так:
      if (auto v = value in squares) writeln( v );