h = {foo: {bar: 1}}
如何設置bar
,如果你不知道你有多少個鍵有哪些?
例如:keys = [:foo, :bar]
h[keys[0]][keys[1]] = :ok
但是,如果密鑰可以是任意長度和H的任意深度的?
h = {foo: {bar: 1}}
如何設置bar
,如果你不知道你有多少個鍵有哪些?
例如:keys = [:foo, :bar]
h[keys[0]][keys[1]] = :ok
但是,如果密鑰可以是任意長度和H的任意深度的?
2.3及更高版本,那麼你可以使用正是如此:
h.dig(*keys[0..-2])[keys.last] = :ok
通過哈希並返回遵循路徑它發現了什麼。但將不會複製它發現的內容,因此您可以獲得h
中的相同參考。 keys[0..-2]
抓取keys
的最後一個元素,因此h.dig(*keys[0..-2])
會給出h
中的{bar: 1}
哈希值,那麼您可以通過簡單的賦值對其進行就地修改。
你也可以說:
*head, tail = keys
h.dig(*head)[tail] = :ok
如果這不是[0..-2]
更清晰的給你。
如果沒有做,那麼你可以做這樣的事情:
*head, tail = keys
head.inject(h) { |m, k| m[k] }[tail] = :ok
當然,如果你不能確定由keys
指定的路徑存在,那麼你就需要在扔一些nil
檢查和決定你應該如何處理keys
沒有指定到h
的路徑。
我正在嘗試使用dig,但無法弄清楚如何完成這個任務。我真的很喜歡你的方法 – Anthony
不錯。我發現'h.dig(* head)[tail] =:ok'更具可讀性。 –
我想出了'path = keys.dup; last_key = path.pop',但'* head,tail = keys'更好。 –
你可以做到這一點遞歸是這樣的:如果你使用Ruby
h = {foo: {bar: 1}}
keys = [:foo, :bar]
h2 = {
foo: {
bar: {
baz: {
setting: :bad
}
}
}
}
keys2 = [:foo, :bar, :baz, :setting]
def set_nested_value(hash, keys, new_val)
if keys.length == 1
hash[keys.first] = new_val
return
end
keys.each_with_index do |key, i|
if hash[key]
set_nested_value(hash[key], keys[i+1..-1], new_val)
end
end
end
set_nested_value(h, keys, :ok)
p h
=> {:foo=>{:bar=>:ok}}
set_nested_value(h2, keys2, :good)
p h2
=> {:foo=>{:bar=>{:baz=>{:setting=>:good}}}}
@ muistooshort有最好的答案。
只是爲了好玩,這裏是一個創造性的:
h = { baz: { foo: { bar: 1 } } }
ObjectSpace.each_object(Hash).find { |h| h.key?(:bar) }[:bar] = :ok
puts h
#=> {:baz=>{:foo=>{:bar=>:ok}}}
免責聲明:不這樣做。 ;)
你問,給定一個鍵列表(在一個數組中),設置最後一個鍵的值? – Anthony
@Anthony - 是的。這更簡潔。 –