Ruby数组要哈希

时间:2012-10-18 23:16:11

标签: ruby

我有以下数组:

myarray = [
  ['usa','primary', 'john'],
  ['france','primary', 'lira'],
  ['usa', 'secondary', 'steve'],
  ['germany', 'primary', 'jeff'],
  ['france', 'secondary', 'ben']
]

我想将其转换为哈希数组,如:

[
  {:country => 'usa', :primary => 'john', :secondary => 'steve'},
  {:country => 'france', :primary => 'lira', :secondary => 'ben'},
  {:country => 'germany', :primary => 'jeff', :secondary => ''}
]

我可以通过遍历数组并将值放入“primary”的哈希来实现。如何将“secondary”添加到可能已插入数组的现有哈希中?

2 个答案:

答案 0 :(得分:11)

稍微高阶编程:

myarray.reduce({}) do |accu, (country, func, name)| 
  accu[country] ||= {}
  accu[country][func.to_sym] = name
  accu 
end.map{|k, h| h[:country] = k; h}

说明:

Reduce将采用累加器,在这种情况下,我们从空哈希开始并遍历数组。我们将数组中的三元组与变量country, func, name匹配。由于我们希望按国家/地区分组,因此我们将其创建为第一个Hash密钥。它应该包含一个哈希,所以我们确保它对应一个accu[country] ||= {}的数组。

然后我们添加将func转换为符号的键值对。最后,我们返回将被传递给下一次迭代的修改累加器。

这将返回如下数据结构:

{"usa"=>{:primary=>"john", :secondary=>"steve"}, 
 "france"=>{:primary=>"lira", :secondary=>"ben"}, 
 "germany"=>{:primary=>"jeff"}} 

现在我们需要将它转换为散列数组而不是大散列。我们通过调用map来执行此操作,并在此过程中添加country作为哈希的键。

现在,上面的算法没有做的一件事是检查缺失值,resp。它并不保证:primary:secondary都存在。你可以通过将map修改为:

来实现
.map do |k, h|
  h[:country] = k
  h[:primary] ||= ""
  h[:secondary] ||= ""
  h
end

答案 1 :(得分:5)

这是一种有趣的,虽然令人困惑的方式。

format = Hash.new{ |h,k| h[k] = {:country => k, :primary => '', :secondary => ''} }

myarray.inject(format){ |result, (c,k,v)| result[c][k.to_sym] = v; result }.values

# => [
  {:country=>"usa", :primary=>"john", :secondary=>"steve"},
  {:country=>"france", :primary=>"lira", :secondary=>"ben"},
  {:country=>"germany", :primary=>"jeff", :secondary=>""} ]

基本上format哈希定义了您想要生成输出的方式。 inject来电按国家/地区收集结果。 values调用只是在没有国家/地区哈希键的情况下获取实际结果。