Вопрос

Создание хэшей хэшей в 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']
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top