2011-12-12 140 views
2

讓我們說我從API取回一個JSON嵌套散列(或散列數組)用nils遍歷ruby嵌套散列?

@example = {"results" = > {{"poop" => "shoop"},{"foo" => {"shizz" => "fizz", "nizzle"=>"bizzle"}}} 

YAML標記中嵌套的哈希上述

- poop: shoop 
    - foo: 
    shizz: fizz 
    nizzle: bizzle 

現在讓我們去作數據庫條目與ActiveRecord哈希。這工作正常。

Thing.create!(:poop => @example["results"]["poop"], 
       :shizz => @example["results"]["foo"]["shizz"], 
       :nizzle=> @example["results"]["foo"]["nizzle"]) 

但是如果'foo'爲空或無?例如,如果一個API結果有一個帶有「名字」,「姓氏」#等的「person」散列,那麼如果沒有數據,那麼「person」散列通常是空的,這意味着它內部的散列不會「不存在。

@example = {"results" = > {{"poop" => "shoop"},{"foo" => nil }} 

    Thing.create!(:poop => @example["results"]["poop"], 
       :shizz => @example["results"]["foo"]["shizz"], 
       :nizzle=> @example["results"]["foo"]["nizzle"]) 

    NoMethodError: You have a nil object when you didn't expect it! 
    You might have expected an instance of Array. 
    The error occurred while evaluating nil.[] 

處理這個問題的最好方法是什麼?

回答

5

我來過一個nil敏感Hash#get方法一會兒回來。

class Hash 
    def get(key, default=nil) 
    key.split(".").inject(self){|memo, key_part| memo[key_part] if memo.is_a?(Hash)} || default 
    end 
end 

h = { 'a' => { 'b' => { 'c' => 1 }}} 
puts h.get "a.b.c" #=> 1 
puts h.get "a.b.c.d" #=> nil 
puts h.get "not.here" #=> nil 

對於這種JSON鑽井來說非常方便。

否則你必須做這樣的東西:

h['a'] && h['a']['b'] && h['a']['b']['c'] 

而這只是吮吸。

+0

確實很有趣,如何「耗盡」備忘錄散列 – maprihoda

+0

光滑 - 這將派上用場 – klochner

+0

所以我會製作一個自定義的類來擴展系統的哈希類,或者我會將這個'get'方法的猴子修補成「哈希」? – thoughtpunch

2

如果您使用的軌道(不知道它在紅寶石1.9):

h = {"a"=>1} 
h.try(:[],"a") #1 
h.try(:[],"b") #nil 

h2 = {"c"=>{"d"=>1}} 
h2.try(:[],"c").try(:[],"d") #1 
h2.try(:[],"a").try(:[],"foo") #nil 

# File activesupport/lib/active_support/core_ext/object/try.rb, line 28 
def try(*a, &b) 
    if a.empty? && block_given? 
    yield self 
    else 
    __send__(*a, &b) 
    end 
end 

+0

我喜歡Rails應用程序的這種解決方案,但我正在尋找更低級別的純Ruby解。我會試試這個,謝謝! – thoughtpunch

1

我繼續開始通過所有的Hash結果爲Hashie Mash。這樣他們的行爲就像Ruby對象,並像冠軍一樣對nils做出響應!

0

紅寶石2.3.0引入a new method called digHashArray完全解決了這個問題。

value = hash.dig(:a, :b) 

如果密鑰在任何級別缺失,則返回nil