Хэши хэшей идиомы в Ruby?

Создание хэшей хэшей в 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 для выполнения этой задачи?

Есть ли хэш хеш-идиом, который возвращал бы 0 после определенной глубины? (Я считаю и использую h [: foo] [: bar] [: baz] + = 1)

Andrew Grimm 11.01.2010 03:15
Пошаговое руководство по созданию собственного Slackbot: От установки до развертывания
Пошаговое руководство по созданию собственного Slackbot: От установки до развертывания
Шаг 1: Создание приложения Slack Чтобы создать Slackbot, вам необходимо создать приложение Slack. Войдите в свою учетную запись Slack и перейдите на...
34
1
5 259
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Ответ принят как подходящий

Вы можете передать функции Hash.new блок, который выполняется для получения значения по умолчанию в случае, если запрошенное значение еще не существует:

h = Hash.new { |h, k| h[k] = Hash.new }

Конечно, это можно сделать рекурсивно. Есть статья, объясняющая детали.

Для полноты картины вот решение из статьи для хешей произвольной глубины:

hash = Hash.new(&(p = lambda{|h, k| h[k] = Hash.new(&p)}))

Первоначально это решение придумал Кент Сибилев.

Мертвая ссылка. Впрочем, впечатляющее решение.

Dean Radcliffe 31.12.2010 18:58

Мертвое звено здесь переключается requestylabs.com/blog2009/2006/09/20/…

Autodidact 24.02.2011 06:34

Эта ссылка также теперь мертва :-(

Adam Spiers 30.07.2013 16:15

Вот ссылка на него в Internet Archive Wayback Machine. По крайней мере, это должно остаться ненадолго! web.archive.org/web/20090331170758/http://blog.inquirylabs.c‌ om /…

Br.Bill 06.12.2019 03:44

@ Br.Bill Действительно, спасибо, я его отредактировал. Для небольших исправлений, подобных этой, не стесняйтесь выполнять редактирование самостоятельно.

Konrad Rudolph 06.12.2019 13:16

Автовивификация, как ее называют, одновременно и благословение, и проклятие. Проблема может заключаться в том, что если вы «посмотрите» на значение до того, как оно будет определено, вы застрянете с этим пустым хешем в слоте, и вам нужно будет удалить его позже.

Если вы не возражаете против небольшой анархии, вы всегда можете просто вставить объявления стилей or-equals, которые позволят вам построить ожидаемую структуру по мере того, как вы ее запрашиваете:

((h ||= { })['w'] ||= { })['z']

require 'xkeys'
h = {}.extend XKeys::Hash

h['x', 'y'] = value_to_insert
looked_up_value = h['w', 'z'] # nil

h[:foo, :bar, :baz, :else => 0] += 1

Другие вопросы по теме

ColdFusion: выберите первое ненулевое значение из списка
Как написать (простую) переменную «toggle»?
Есть ли учебное пособие, которое обучает распространенным идиомам программирования на Ruby, используемым опытными программистами, но может быть неочевидным для новичков?
Рубиновые идиомы для использования параметров командной строки
Как написать ctor для класса, владеющего типами nocopy-nomove, один из которых должен быть инициализирован из другого, который может быть одним из нескольких типов?
Существует ли идиома Pandas для чтения файла CSV с категориальными данными, имеющими варианты написания?
Каков в Rust идиоматический способ связать члены одного перечисления с другими типами перечислений и сопоставить их целочисленные и строковые представления?
Как остановить вызов карты, если вложенный поиск возвращает None?
Концепция скрытого друга в C++
Был ли это идиоматический способ определения частичных функций в Perl?