3 votes

Définition récursive de clés de hachage à partir d'un tableau de clés

Je veux une fonction qui puisse prendre un tableau comme [:a, :b, :c] et définit récursivement des clés de hachage, en créant ce dont il a besoin au fur et à mesure.

hash = {}

hash_setter(hash, [:a, :b, :c], 'value') 
hash #=> {:a => {:b => {:c => 'value' } } }

hash_setter(hash, [:a, :b, :h], 'value2') 
hash #=> {:a => {:b => {:c => 'value', :h => 'value2' } } }

Je suis conscient que la fonction dig peut être utilisé pour obtenir de cette manière, bien que cela ne permette pas d'obtenir une réponse. S'il existait un équivalent de dig pour le setter, c'est ce que je chercherais.

0voto

Cary Swoveland Points 6784

Code

def nested_hash(keys, v, h={})
  return subhash(keys, v) if h.empty?
  return h.merge(subhash(keys, v)) if keys.size == 1
  keys[0..-2].reduce(h) { |g,k| g[k] }.update(keys[-1]=>v)
  h
end

def subhash(keys, v)
  *first_keys, last_key = keys
  h = { last_key=>v }
  return h if first_keys.empty?
  first_keys.reverse_each.reduce(h) { |g,k| g = { k=>g } }
end

Exemples

h = nested_hash([:a, :b, :c], 14)    #=> {:a=>{:b=>{:c=>14}}}
i = nested_hash([:a, :b, :d], 25, h) #=> {:a=>{:b=>{:c=>14, :d=>25}}}
j = nested_hash([:a, :b, :d], 99, i) #=> {:a=>{:b=>{:c=>14, :d=>99}}}
k = nested_hash([:a, :e], 104, j)    #=> {:a=>{:b=>{:c=>14, :d=>99}, :e=>104}}
    nested_hash([:f], 222, k)        #=> {:a=>{:b=>{:c=>14, :d=>99}, :e=>104}, :f=>222}

Observez que la valeur de :d est remplacée dans le calcul de j . Notez également que :

subhash([:a, :b, :c], 12)
  #=> {:a=>{:b=>{:c=>12}}}

Cela modifie le hachage h . Si cela n'est pas souhaité, il est possible d'insérer la ligne suivante

  f = Marshal.load(Marshal.dump(h))

après la ligne return subhash(keys, v) if h.empty? et modifier les références ultérieures à h à f . Méthodes de la Maréchal peut être utilisé pour créer un copie approfondie d'un hachage afin que le hachage original ne soit pas modifié.

0voto

babonk Points 4878

Résolu grâce à la récursivité :

def hash_setter(hash, key_arr, val)
  key = key_arr.shift
  hash[key] = {} unless hash[key].is_a?(Hash)
  key_arr.length > 0 ? hash_setter(hash[key], key_arr, val) : hash[key] = val
end

-2voto

XAleXOwnZX Points 159
def set_value_for_keypath(initial, keypath, value)
    temp = initial

    for key in keypath.first(keypath.count - 1)
        temp = (temp[key] ||= {})
    end

    temp[keypath.last] = value

    return initial
end

initial = {:a => {:b => {:c => 'value' } } }

set_value_for_keypath(initial, [:a, :b, :h], 'value2')

initial

Ou si vous préférez quelque chose de plus illisible :

def set_value_for_keypath(initial, keypath, value)
    keypath.first(keypath.count - 1).reduce(initial) { |hash, key| hash[key] ||= {} }[keypath.last] = value
end

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X