[英]Ruby hash of hash initialization
考慮@data是ActiveRecords的數組,其字段為date , class , name和grade 。 假設我想以兩個哈希結束,一個是每個名稱中所有日期的唯一集合; 另一個按班級細分,然后按日期,然后按名稱顯示成績。
dates = {}
grades = {}
@data.each do |d|
dates[ d.name ][ d.date ] = '' # 1
grades[ d.class => { d.date => { d.name => d.grade } } ] # 2
end
導致錯誤:
未定義的方法[[] ='for nil:NilClass
dates[ d.name => { d.date => '' } ]
僅存儲最后一條記錄(不會合並到較早的結果中)
不會出錯,但以空哈希{}
結尾
回到Perl之后,我忘記了如何在Ruby中初始化和添加到哈希哈希中。
對於第一個( 日期 ),看起來我可以在循環內執行以下操作:
dates[ d.name ] ||= { d.date => '' }
dates[ d.name ][ d.date ] = ''
查看文檔,我不知道這是否是正確的方法,它似乎效率也不高,因為它將對第一個值進行兩次賦值。 它還建議對於每個鍵,我都需要聲明/初始化基礎數據結構,隨着哈希值的散列值(如等級散列值)的增加,該數據結構將變得冗長。
資源:
[{ name: 'greg', class:'science', date:'jan', grade:'a' },
{ name: 'greg', class:'math' , date:'jan', grade:'b' },
{ name: 'barb', class:'history', date:'jan', grade:'a' },
{ name: 'barb', class:'science', date:'feb', grade:'c' }]
日期看起來像:
{ 'greg' => { 'jan' => '' },
'barb' => { 'jan' => '' ,
'feb' => ''
}
}
成績看起來像:
{ 'science' => { 'jan' => { 'greg' => 'a' } ,
'feb' => { 'barb' => 'c' } },
'math' => { 'jan' => { 'greg' => 'b' } },
'history' => { 'jan' => { 'barb' => 'a' } }
}
這實際上可以正常工作,因為當您嘗試從哈希訪問密鑰時,它不僅返回默認值,還對其進行設置:
Hash.new do |h, k|
h[k] = Hash.new do |hh, kk|
hh[kk] = {}
end
end
更新:
盡管對於未來的開發人員而言,可能比僅檢查是否為nil更混亂,但這可能會更清潔一點。
dates = Hash.new { |hash, key| hash[key] = {} }
grades = Hash.new { |hash, key| hash[key] = dates.clone }
嘗試:
d={}
c=Client.first
d[c.last_name]=[]
d[c.last_name][c.id]=//your value
d [c.last_name] = [],為c.last_name初始化一個哈希數組
我能夠像這樣構建日期哈希:
arr = [{ name: 'greg', class:'science', date:'jan', grade:'a' },
{ name: 'greg', class:'math' , date:'jan', grade:'b' },
{ name: 'barb', class:'history', date:'jan', grade:'a' },
{ name: 'barb', class:'science', date:'feb', grade:'c' }]
dates = arr.group_by { |x| x[:name] }.each_with_object({}) do |(k, v), hash|
dates = v.map { |i| i[:date] }.uniq
dates_hash = dates.each_with_object({}) { |date, h| h[date] = "" }
hash[k] = dates_hash
end
puts dates
{"greg"=>{"jan"=>""}, "barb"=>{"jan"=>"", "feb"=>""}}
碼
要獲取每個:name
的唯一:date
值,您可以使用Hash.update的形式(與merge!
相同),該形式使用哈希確定鍵的值包含在要合並的兩個哈希中:
def dates_by_name(arr)
arr.each_with_object({}) { |g,h|
h.update({g[:name]=>[g[:date]]}) {|_,ov,nv|
ov.include?(nv.first) ? ov : ov + nv}}
end
有許多方法可以按班級,日期和名稱來組織成績等級。 以下采用遞歸:
def grade_by_class_date_name(arr, fields)
fd = fields.dup
f = fd.shift
return arr.first[:grade] if f==:grade
g = arr.each_with_object(Hash.new { |h,k| h[k] = [] }) { |e,g|
g[e[f]] << e.reject { |k,_| k == f } }
g.each_key { |k| g[k] = grade_by_class_date_name(g[k], fd) }
g
end
例子
arr = [{ name: 'greg', class:'science', date:'jan', grade:'a' },
{ name: 'greg', class:'math' , date:'jan', grade:'b' },
{ name: 'barb', class:'history', date:'jan', grade:'a' },
{ name: 'barb', class:'science', date:'feb', grade:'c' }]
dates_by_name(arr)
#=> {"greg"=>["jan"], "barb"=>["jan", "feb"]}
dates_by_name
返回的哈希值不是您要求的格式,但是您可以輕松地對其進行操作以滿足您的要求。
fields = [:class, :date, :name, :grade]
grade_by_class_date_name(arr, fields)
#=> {"science"=>{"jan"=>{"greg"=>"a"},
# "feb"=>{"barb"=>"c"}},
# "math" =>{"jan"=>{"greg"=>"b"}},
# "history"=>{"jan"=>{"barb"=>"a"}}}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.