2013-07-15 84 views
41

什麼是這方面的一個較短的版本?:如何一次獲取多個散列值?

from = hash.fetch(:from) 
to = hash.fetch(:to) 
name = hash.fetch(:name) 
# etc 

注意fetch,我想如果該鍵不存在,引發錯誤。

必須有較短的版本的它,像:

from, to, name = hash.fetch(:from, :to, :name) # <-- imaginary won't work 

這是確定的,如果需要請使用ActiveSupport。

+0

一個重要和沒有提出的問題是。你想從hash到vars重新分配什麼值? –

+0

@MichaelSzyndel我無法解析你的評論。 – sawa

+1

爲什麼你想要做'from = hash.fetch(:from); to = hash.fetch(:to);'...而不是使用'hash [:from]'? –

回答

3
hash = {from: :foo, to: :bar, name: :buz} 

[:from, :to, :name].map{|sym| hash.fetch(sym)} 
# => [:foo, :bar, :buz] 
[:frog, :to, :name].map{|sym| hash.fetch(sym)} 
# => KeyError 
71

用散的values_at方法:

from, to, name = hash.values_at(:from, :to, :name) 

這將返回nil對於不哈希存在任何按鍵。

+4

這不符合OP的要求。 – sawa

+0

@MichaelSzyndel自己閱讀問題。 – sawa

+0

有沒有這樣的方法,將獲取多個鍵和railse例外爲缺少的。其中一個原因可能是 - 什麼時候應該引發異常 - 何時不存在密鑰(可能會爲其他密鑰留下未分配的變量)或者在獲取所有密鑰之後?自己添加這樣的檢查很容易,我也看不出有什麼理由堅持在這裏提出異議。 –

2
my_array = {from: 'Jamaica', to: 'St. Martin'}.values_at(:from, :to, :name) 
my_array.keys.any? {|key| element.nil?} && raise || my_array 

像你這樣要求

my_array = {from: 'Jamaica', to: 'St. Martin', name: 'George'}.values_at(:from, :to, :name) 
my_array.keys.any? {|key| element.nil?} && raise || my_array 

這將返回數組會引發錯誤。

但OP要求未能在缺少鍵...

class MissingKeyError < StandardError 
end 
my_hash = {from: 'Jamaica', to: 'St. Martin', name: 'George'} 
my_array = my_hash.values_at(:from, :to, :name) 
my_hash.keys.to_a == [:from, :to, :name] or raise MissingKeyError 
my_hash = {from: 'Jamaica', to: 'St. Martin'} 
my_array = my_hash.values_at(:from, :to, :name) 
my_hash.keys.to_a == [:from, :to, :name] or raise MissingKeyError 
+1

'my_array.any? {|元素| element.nil?} && raise'會不正確,因爲一個鍵可能存在一個「nil」值。 –

+0

你是對的。我檢查了價值而不是關鍵。我將編輯密鑰。 – vgoff

+0

'keys.to_a == [:from,:to,:name]'不正確。這裏的順序很重要,但哈希鍵沒有特別的順序,它至少應該是'keys.to_a - [:from,:to,:name] == []'。總的來說,這只是比它的價值更多的努力。 –

1

我會去的最簡單的事情將是

from, to, name = [:from, :to, :name].map {|key| hash.fetch(key)} 

另外,如果你想使用values_at,你可以使用帶有默認值塊的Hash

hash=Hash.new {|h, k| raise KeyError.new("key not found: #{k.inspect}") } 
# ... populate hash 
from, to, name = hash.values_at(:from, :to, :name) # raises KeyError on missing key 

或者,如果您這樣的傾向,猴子補丁Hash

class ::Hash 
    def fetch_all(*args) 
    args.map {|key| fetch(key)} 
    end 
end 
from, to, name = hash.fetch_all :from, :to, :name 
+0

這與我的有何不同? – sawa

+0

@sawa顯然,它分配結果哈哈:) –

1

您可以用KeyError對象的默認值初始化的哈希值。如果您嘗試獲取的密鑰不存在,這將返回KeyError的一個實例。所有你需要做的就是檢查它的(值)類,並提高它,如果它的KeyError。

hash = Hash.new(KeyError.new("key not found")) 

我們的一些數據添加到這個哈希

hash[:a], hash[:b], hash[:c] = "Foo", "Bar", nil 

最後看的價值觀和提高一個錯誤,如果沒有找到

hash.values_at(:a,:b,:c,:d).each {|v| raise v if v.class == KeyError} 

此項將引發異常,當且僅當鍵不存在。如果您的密鑰值爲nil,它不會投訴。

+0

我不控制如何創建哈希。所以我將不得不重新創建/複製,以使用「特殊」值作爲無鍵的標記。 –

12

紅寶石2.3最後引入了散列的fetch_values方法直接地實現這一點:

{a: 1, b: 2}.fetch_values(:a, :b) 
# => [1, 2] 
{a: 1, b: 2}.fetch_values(:a, :c) 
# => KeyError: key not found: :c 
相關問題