2012-04-27 37 views
6

Tôi chắc chắn rằng tôi đã thấy một giải pháp thanh lịch cho điều này trước đây, nhưng tôi không thể tìm thấy nó:Thanh lịch xử lý các giá trị trống trong một giá trị băm lồng nhau

Tôi có bộ điều khiển ray có thể-hoặc-có thể -không có phần tử băm sau:

myhash[:parent_field] 

Bên trong trường chính đó, phần tử con cũng có thể để trống. Tôi hiện đang kiểm tra thông qua phương pháp (rất xấu xí):

if (!myhash[:parent_field] || !myhash[:parent_field][:child_field] || myhash[:parent_field][:child_field].blank?) 

Công trình nào, nhưng tôi chắc chắn - phải có cách thanh lịch hơn. Chỉ cần nhắc lại:

  • myhash [: parent_field] có thể hoặc không thể tồn tại
  • Nếu nó không tồn tại, myhash [: parent_field] [: child_field] có thể có hoặc không tồn tại
  • Nếu tồn tại, nó có thể hoặc không được để trống.

Trả lời

9

#fetch là bạn của bạn:

my_hash.fetch(:parent, {})[:child].blank? 
+0

Lưu ý rằng điều này sẽ làm tăng ngoại lệ nếu phím ': parent' không tồn tại. –

+0

@AndrewMarshall Không, không. Đọc về những gì tìm nạp. – d11wtq

+0

Xin lỗi, không thấy đối số thứ hai ở đó. Nó sẽ nếu không có, mặc dù. –

0

Nó có thể phụ thuộc vào nhu cầu thực tế của bạn là gì, nhưng cách tiếp cận OOP cho điều này là chuyển đổi mảng và băm thành đối tượng thực. Mỗi đối tượng sẽ quản lý các mối quan hệ của nó (tương tự như ActiveRecord), và sẽ biết cách để có được trẻ em và cha mẹ.

3

gì tôi sẽ làm chỉ là sử dụng các biến địa phương để giảm bớt gánh nặng của bạn:

unless (p=foo[:parent]) && (c=p[:child]) && !c.blank? 
    # Stuff is borked! 
end 

Nhưng chúng ta hãy cùng khám phá giải pháp thay thế, cho vui & hellip;


Nếu bạn không thể thay đổi cấu trúc dữ liệu của bạn (đó là một Hash, bằng cách này, không phải là một Array) sau đó bạn có thể sử dụng Ruby andand đá quý kết hợp với try cách như lười biếng gọi của Rails phương pháp trên những thứ có thể là nil đối tượng.


Hoặc bạn có thể thay đổi cấu trúc dữ liệu của bạn để băm mà trở về băm tự động sống động trống rỗng khi bạn yêu cầu một chìa khóa mà không tồn tại:

mine = Hash.new{ |h,k| Hash.new(&h.default_proc) } 
mine[:root] = { dive:42 } 
p mine[:root][:dive]  #=> 42 
p mine[:ohno][:blah][:whee] #=> {} 
p mine[:root][:blah][:whee] #=> undefined method `[]' for nil:NilClass (NoMethodError) 

Tuy nhiên, bạn phải đảm bảo rằng mọi đối tượng trong hệ thống phân cấp của bạn là một trong những thứ băm này (mà tôi đã thất bại một cách rõ ràng đối với nội dung của :dive, dẫn đến lỗi).


Đối với niềm vui thay thế, bạn có thể thêm phương pháp tra cứu kỳ diệu của riêng bạn:

class Hash 
    def divedive(*keys) 
    obj = self 
    keys.each do |key| 
     return obj unless obj && obj.respond_to?(:[]) 
     obj = obj[key] 
    end 
    obj 
    end 
end 

if myarray.divedive(:parent,:child).blank? 
    # ... 
-2

Làm thế nào về

!(myarray[:parent_field][:child_field] rescue nil).blank? 

?

0

Kể từ nil.blank?true, bạn có thể loại bỏ các điều kiện trung bình và đơn giản hóa như sau:

if !myarray[:parent_field] || myarray[:parent_field][:child_field].blank? 

Ngoài ra, gọi một Hash myarray là một chút sai lệch.

1

Đây là một câu hỏi thường gặp và có lẽ nên được đóng lại như một bản sao của

Đầu tiên trong danh sách đó đã được đóng cửa như một dup của hai người kia, mặc dù tôi tin rằng câu trả lời của tôi có phạm vi bảo hiểm toàn diện hơn về các kỹ thuật để giải quyết vấn đề này hơn là sau này o.

+0

Darn - bạn nói đúng. Tôi đã thử tìm kiếm, nhưng không thể đưa ra bất cứ điều gì có liên quan. Tôi đã bỏ phiếu để đóng. Và cảm ơn rất nhiều. :-) – PlankTon

Các vấn đề liên quan