Hashes de hashes Idiom em Ruby?
-
05-07-2019 - |
Pergunta
Criando hashes de hashes em Ruby permite pesquisas dimensionais convenientes dois (ou mais). No entanto, quando se insere uma necessidade sempre verificar se o primeiro índice já existe no hash. Por exemplo:
h = Hash.new
h['x'] = Hash.new if not h.key?('x')
h['x']['y'] = value_to_insert
Seria preferível fazer o seguinte, onde o novo Hash é criado automaticamente:
h = Hash.new
h['x']['y'] = value_to_insert
Da mesma forma, quando se olha-se um valor em que o primeiro índice já não existir, seria preferível se nil é retornado ao invés de receber um método não definido para erro '[]'.
looked_up_value = h['w']['z']
Pode-se criar um Hash invólucro de classe que tem esse comportamento, mas existe um já existente uma linguagem Ruby para realizar esta tarefa?
Solução
Você pode passar a função Hash.new
um bloco que é executado para produzir um valor padrão no caso do valor consultado ainda não existe:
h = Hash.new { |h, k| h[k] = Hash.new }
Claro, isso pode ser feito de forma recursiva.
/ EDIT: Uau, há um artigo responder a esta pergunta muito.
Por uma questão de exaustividade, aqui está a solução do artigo para hashes profundidade arbitrária:
hash = Hash.new(&(p=lambda{|h,k| h[k] = Hash.new(&p)}))
Os créditos vão para Kent de Dados Noise .
Outras dicas
Autovivification, como é chamado, é uma bênção e uma maldição. O problema pode ser que se você "olhar" para um valor antes de ser definido, você está preso com esse hash vazio no slot e você precisa podar-lo mais tarde.
Se você não se importa um pouco de anarquia, você pode sempre congestionamento na ou-iguala declarações de estilo que lhe permitirá construir a estrutura esperada como você consultá-lo:
((h ||= { })['w'] ||= { })['z']