哈希初始化的Ruby哈希

时间:2015-01-13 22:53:43

标签: ruby-on-rails ruby hash

考虑@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
  1. 导致错误:

      

    未定义的方法`[] ='为nil:NilClass

    dates[ d.name => { d.date => '' } ]仅存储最后一条记录(不会合并到较旧的结果中)

  2. 没有错误,但以空哈希{}

  3. 结尾

    回到Perl之后,我忘记了如何初始化并添加到Ruby中哈希的散列。


    更新

    对于第一个( date ),看起来我可以在循环中执行以下操作:

    dates[ d.name ] ||= { d.date => '' }
    dates[ d.name ][ d.date ] = ''
    

    查看文档,我不知道这是否是正确的方法,它似乎效率低下,因为它将为第一个值执行两次赋值。它还建议对于每个键,我需要声明/初始化底层数据结构,哈希散列的深度越长(如 grade 哈希)。


    来源:

    [{ 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' } }
    }
    

4 个答案:

答案 0 :(得分:0)

这实际上会起作用,因为当您尝试从散列中访问密钥时,它不仅会返回默认值,还会设置它:

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 }

答案 1 :(得分:0)

尝试:

d={}
c=Client.first
d[c.last_name]=[]
d[c.last_name][c.id]=//your value

d [c.last_name] = [],初始化c.last_name

的哈希数组

答案 2 :(得分:0)

我能够像这样构建日期哈希:

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"=>""}}

答案 3 :(得分:0)

<强>代码

要获取每个:date的唯一:name值,您可以使用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"}}}