Хэши хэшей идиома в рубине?
-
05-07-2019 - |
Вопрос
Создание хэшей хэшей в Ruby позволяет осуществлять удобный (или более) двухмерный поиск. Однако при вставке всегда нужно проверять, существует ли первый индекс в хэше. Например:
h = Hash.new
h['x'] = Hash.new if not h.key?('x')
h['x']['y'] = value_to_insert
Было бы предпочтительно сделать следующее, когда новый хеш создается автоматически:
h = Hash.new
h['x']['y'] = value_to_insert
Аналогичным образом, при поиске значения, в котором первый индекс еще не существует, было бы предпочтительнее, если возвращается nil, а не получает неопределенный метод для ошибки '[]'. Р>
looked_up_value = h['w']['z']
Можно создать класс-оболочку Hash с таким поведением, но существует ли идиома Ruby для выполнения этой задачи?
Решение
Вы можете передать Hash.new
функция блок, который выполняется для получения значения по умолчанию в случае, если запрашиваемое значение еще не существует:
h = Hash.new { |h, k| h[k] = Hash.new }
Конечно, это можно сделать рекурсивно.
/ РЕДАКТИРОВАТЬ: вау, есть статья отвечаю на этот вопрос.
Для полноты, вот решение из статьи для произвольных хэшей глубины:
hash = Hash.new(&(p=lambda{|h,k| h[k] = Hash.new(&p)}))
Кредиты поступают в Кент с шума данных .
Другие советы
Автовивификация, как ее называют, является и благословением, и проклятием. Проблема может заключаться в том, что если вы «посмотрите» со значением до его определения, вы застряли с этим пустым хешем в слоте, и вам понадобится удалить его позже.
Если вы не возражаете против некоторой анархии, вы всегда можете просто заклинить объявления стиля or-equals, которые позволят вам построить ожидаемую структуру при ее запросе:
((h ||= { })['w'] ||= { })['z']