Ruby数组转哈希表

5

我有以下数组:

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个回答

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进行匹配。因为我们要按照国家分组,所以我们将其作为第一个哈希键。它应该包含一个哈希,因此我们确保它对应一个具有accu[country] ||= {}的数组。

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

这将返回以下数据结构:

{"usa"=>{:primary=>"john", :secondary=>"steve"}, 
 "france"=>{:primary=>"lira", :secondary=>"ben"}, 
 "germany"=>{:primary=>"jeff"}} 
现在我们需要将它转换为哈希数组而不是一个大的哈希表。我们通过对其调用map来完成此操作,并在此过程中将country添加为哈希表的键。
现在,上述算法没有检查缺失值或者保证:primary:secondary都存在。你可以通过将map修改为以下内容来实现:
.map do |k, h|
  h[:country] = k
  h[:primary] ||= ""
  h[:secondary] ||= ""
  h
end

谢谢。但是在这里,你把国家名称放在外面了,例如 "usa"=>{:primary=>"john", :secondary=>"steve"},而我希望有 {:country => 'usa', :primary => 'john', :secondary => 'steve'}。 - JVK
尝试运行代码,它确实做到了这一点。我在答案中谈论的是reducemap之间的中间步骤。请仔细阅读。 - Jakub Hampl
你太棒了,但是让我问一下,如果我们有更多的身份需要分组怎么办。例如,我的数组 = [['usa', 'california', 90072, 'primary', 'john'], ['usa', 'california', 90072, 'secondary', 'paul'], ['france', 'brittany', 73829, primary', 'lira']]这意味着如果我需要根据不止一个列进行分组,不只是国家。要按国家、州和邮政编码分组 :) - JVK
你可以将数组用作哈希键,所以不仅仅是accu[country],你可以使用由所有这些值组成的数组作为键。 - Jakub Hampl

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调用仅获取实际结果而不包括国家/地区哈希键。

+1 我在想是否有人会使用 Hash.new 这个东西。 - Jakub Hampl

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接