2012-04-27 32 views
6

我敢肯定,我以前見過一個優雅的解決方案,但我不能完全找到它:典雅的處理嵌套散列空白值

我有一個Rails控制器,可有或可能 - 不具有以下散列元素:

myhash[:parent_field] 

在該父字段內,子元素也可以爲空。我目前正在檢查通過(非常難看)方法:

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

其中一期工程,但我想 - 肯定 - 必須有一個更優雅的方式。只是重申:

  • myhash [:parent_field]可能會或可能不存在
  • 如果它確實存在,myhash [:parent_field] [:child_field]可能會或可能不存在
  • 如果存在,它可能會或可能不會是空白的。

回答

9

#fetch是你的朋友:

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

請注意,如果':parent'鍵不存在,則會引發異常。 – 2012-04-28 02:26:41

+0

@AndrewMarshall不,它不會。閱讀什麼取回。 – d11wtq 2012-04-28 02:48:41

+0

對不起,沒有看到第二個參數。不過,如果沒有的話。 – 2012-04-28 02:57:13

0

這可能取決於你的實際需求是什麼,但是OOP的方法是將數組和哈希轉換爲實際對象。每個對象都會管理它的關係(類似於ActiveRecord),並且知道如何讓孩子和父母。

3

我會做什麼只是使用局部變量,以減輕你的負擔:

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

但是,讓我們探索的替代品,爲樂趣…


如果你不能改變你的數據結構(這是一個Hash,順便說一下,不是數組),那麼你可以使用紅寶石andand寶石與Rails的try調用的懶辦法配合方法上的東西可能是nil對象。


你可以你的數據結構或者改變哈希當你問一鍵返回空自動充滿生機的哈希值不存在:

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) 

但是,你必須確保層次結構中的每個對象都是這些散列中的一個(我明確沒有爲:dive的內容執行操作,導致錯誤)。


對於另類的樂趣,你可以添加你自己的法寶查找方法:

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

如何

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

0

由於nil.blank?true,可以去除中間狀態,並簡化到這一點:

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

此外,調用哈希myarray是有點誤導。

1

這是一個經常被問到的問題,或許應該停課時

在該列表中的第一個副本被關閉的DUP另外兩個,但我相信我的答案比後面的答案更全面地解決這個問題O操作。

+0

該死 - 你說得對。我確實嘗試過搜索,但無法提出任何相關的內容。我已投票結束。並且非常感謝。 :-) – PlankTon 2012-04-28 00:27:29