2013-07-15 23 views
41

là gì một phiên bản ngắn hơn này ?:Làm cách nào để tìm nạp nhiều giá trị băm cùng một lúc?

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

Lưu ý fetch, tôi muốn nâng cao một lỗi nếu chìa khóa không tồn tại.

Phải có phiên bản ngắn hơn của nó, như:

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

It is OK để sử dụng ActiveSupport nếu cần thiết. values_at phương pháp

+0

Một câu hỏi quan trọng và không được yêu cầu là. Bạn muốn gán lại các giá trị từ hàm băm cho vars cho điều gì? –

+0

@MichaelSzyndel Tôi không thể phân tích cú pháp nhận xét của bạn ở trên. – sawa

+1

Tại sao bạn muốn làm 'from = hash.fetch (: from); to = hash.fetch (: to); '... thay vì sử dụng' hash [: from] '? –

Trả lời

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

Sử dụng Hash của:

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

này sẽ trở lại nil cho bất kỳ khóa không tồn tại trong băm.

+4

Điều này không đáp ứng yêu cầu của OP. – sawa

+0

@MichaelSzyndel Đọc câu hỏi của chính bạn. – sawa

+0

Không có phương pháp nào như vậy sẽ tìm nạp nhiều khóa và ngoại lệ lan can cho các khóa bị thiếu. Một trong những lý do có thể là - khi ngoại lệ nên được nâng lên - khi khóa không tồn tại (nó có thể để lại các biến chưa được gán cho các khóa khác) hoặc sau khi tìm nạp tất cả các khóa? Thật dễ dàng để thêm kiểm tra như vậy của chính mình và tôi không thể thực sự thấy bất kỳ lý do tại sao nhấn mạnh vào việc nâng cao ngoại lệ ở đây. –

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

này sẽ nâng cao một lỗi như bạn yêu cầu

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

này sẽ trở lại mảng.

Nhưng OP hỏi cho thất bại trên một phím mất tích ...

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 | element.nil?} && raise' sẽ không chính xác vì khóa có thể tồn tại với giá trị 'nil'. –

+0

Bạn đúng. Tôi đã kiểm tra giá trị thay vì khóa. Tôi sẽ chỉnh sửa cho khóa. – vgoff

+0

'keys.to_a == [: from,: to,: name]' không chính xác. Thứ tự sẽ quan trọng ở đây, nhưng các khóa Hash không có thứ tự cụ thể, nó phải có ít nhất 'keys.to_a - [: from,: to,: name] == []'. Nhìn chung, nó chỉ là nỗ lực nhiều hơn giá trị của nó. –

1

Điều đơn giản nhất tôi sẽ đi cho sẽ là

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

Ngoài ra, nếu bạn muốn sử dụng values_at, bạn có thể sử dụng một số Hash với khối giá trị mặc định:

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 

Hoặc, nếu bạn nghiêng như vậy, khỉ vá Hash

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

Điều này khác với tôi như thế nào? – sawa

+0

@sawa rõ ràng, nó gán kết quả LOL :) –

1

Bạn có thể khởi băm của bạn với một giá trị mặc định của KeyError đối tượng. Điều này sẽ trả về một thể hiện của KeyError nếu khóa bạn đang tìm nạp không có mặt. Tất cả những gì bạn cần làm là kiểm tra lớp (value's) của nó và nâng nó lên nếu nó là một KeyError.

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

Hãy thêm một số dữ liệu để băm này

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

Cuối cùng nhìn vào các giá trị và nâng cao một lỗi nếu chủ chốt không tìm thấy

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

này sẽ nâng cao một ngoại lệ khi và chỉ khi không có chìa khóa. Nó sẽ không khiếu nại trong trường hợp bạn có một khóa với giá trị nil.

+0

Tôi không kiểm soát cách Hash được tạo. Vì vậy, tôi sẽ phải tạo lại/sao chép chỉ để sử dụng giá trị "đặc biệt" làm điểm đánh dấu không có khóa. –

12

của Ruby 2.3 cuối cùng giới thiệu các phương pháp fetch_values cho băm mà thẳng thắn đạt được điều này:

{a: 1, b: 2}.fetch_values(:a, :b) 
# => [1, 2] 
{a: 1, b: 2}.fetch_values(:a, :c) 
# => KeyError: key not found: :c 
Các vấn đề liên quan