Найти тему
Блокнот математика

Рубрика "Секреты Вим". Словари и объекты

Привет, коллеги. Продолжаем углубляться в скриптовый язык Вим. Сегодня обсудим словари. В предыдущей заметке есть ссылки на более ранние материалы. И путеводитель к Вашим услугам.

Принцип схож: ключ-значение.
Принцип схож: ключ-значение.

Словарь, он же ассоциативный массив, он же хэш — это множество значений, доступных по ключам (а не по номерам). Такие структуры данных есть во многих скриптовых языках. Отличие от массива (которых в Виме вообще нет) и списка в том, что это неупорядоченная структура пар ключ-значение.

Ключи могут быть числами, но вообще это строки.

Создается словарь перечислением пар ключ:значение в фигурных скобках через запятую:

let mydict = {'nome': 'Taccuino', 'connome':'Matematica', 'eta':43}

Словари могут быть вложенными.

Доступ к элементам похож на списки: через квадратные скобки: mydict['nome']. Однако если ключ является идентификатором (состоит из букв, цифр, символа _), то можно упростить запись: mydict.nome.

Функция keys возвращает список ключей словаря, и можно циклом for перебрать все элементы:

for key in keys(mydict)

или

for key in sort(keys(mydict))

Есть функция values, которая возвращает список значений, превращая словарь в список. Порядок заранее не определен, так что в разных случаях могут получиться разные списки. Ну, сортируйте)

Наконец, есть функция items, которая возвращает список списков из двух элементов "ключ-значение", и синтаксис

for [key, val] in items(mydict)

позволит с комфортом перебрать все пары.

Проверить наличие ключа в словаре позволяет has_key.

Всё сказанное про копирование и сравнение списков относится и к словарям, а именно: переменная со словарем является указателем на него, и присваивание другой переменной делает ее указателем на тот же словарь. Функция copy создает новый экземпляр словаря, однако значения, если они сами словари (или списки), не копируются. Функция deepcopy копирует всё рекурсивно. Кроме того, при сравнении словарей конвертация чисел и строк не происходит, так что словарь {'uno':1} не равен словарю {'uno':'1'}.

Удалить ключ вместе со значением позволяет функция remove или unlet, как и у списков.

Функция extend позволяет слить два словаря, перезаписывая значения совпадающих ключей в первом. Третий необязательный аргумент может иметь значение 'keep' (сохраняется значение первого словаря, теряется второго), 'forse' (по умолчанию, используется значение второго), 'error' (ситуация приводит к ошибке). Первый словарь меняется! Добавленные ключи необязательно идут после старых.

Фильрация списков filter работает и для словарей, причем кроме v:val доступна и переменная v:key. Она позволяет отобрать те пары, которые подходят под какое-то условие.

То же касается функций map и count (первая позволяет пройтись по словарю, что-то делая с его элементами, а вторая считает элементы, подпадающие под условие).

Функции min и max работают для словарей, как и len (максимальное и минимальное значение и число элементов).

Словари могут содержать ссылки на функции и это очень близко к инкапсуляции ООП. Если при определении функции указать атрибут dict, то словарь, из которого функция вызвана, передается как параметр self.

А можно просто определить функцию как элемент словаря:

function mydict.len()
return len(keys(self))
endfunction

Функция получит номер и под этим номером ее можно посмотреть: function {6}

До "истинного" ООП Виму, конечно, далеко, да он и не претендует. Но создать словари с встроенными функциями можно, и это будут вполне себе объекты, по всем правилам инкапсуляции. И наследование будет, так как можно сделать копию словаря и добавить/переопределить элементы или функции. Даже полиморфизм в зачатке есть, поскольку если функция принимает словарь и считает его таким-то, то и его потомки тоже сгодятся как аргументы этой функции.

Последний нюанс. Переменные могут, как мы уже обсуждали, иметь префикс, который описывает их область видимости. Иногда префикс необходим, как в случае системных переменных Вим (v:), аргументов функции (a:) или локальных для буфера переменных (b:), иногда необязателен (если переменная глобальна, то g: не повредит, но не необходим). Так вот, префикс сам по себе является словарем, в котором и присутствуют все переменные. Например, попробуйте

echo items(b:)
echo keys(v:)

Это довольно удобно иногда.

Пример работы со словарями. Часто бывает надо перевести число в текстовую форму. Например, при редактировании стиля: небольшие числа принято записывать текстом: "девять девушек", а не "9 девушек". Поможем себе:

function NToWord(n)
let eng = {1: 'one', 2: 'two', ...}
return eng[a:n]
endfunction
map ,w v"vy:let @v=NToWord(@v)<CR>v"vp
vmap ,w "vd:let @v=NToWord(@v)<CR>"vp

Теперь однозначные числа можно легко заменить английскими названиями этих чисел, нажав комбинацию ,w. Для русских это тоже делается, но надо учесть тройственность единицы (один, одна, одно) и двойственность двойки (два, две). Фантазируйте!

Научно-популярные каналы на Дзене: путеводитель
Новости популярной науки12 марта 2022