帮助重新分解Ruby散列切片和切块

时间:2011-09-03 17:54:34

标签: ruby hash

我正在开展一个项目,我需要将报纸文章与它们在印刷品中出现的页码相关联。

我的输入数据只是一堆文章标题和页码。我想出了以下代码来创建一个新的Hash,其中键是页码,值是文章标题的数组:

a = ["A1", "title 1"]
b = ["A1", "title 2"]
c = ["A2", "title 3"]
hash = {}
articles = [a,b,c]
articles.each do |a|
  if hash.has_key?(a[0])
    hash[a[0]] << a[1]
  else
    hash.merge!({a[0] => [a[1]]})
  end
end

代码运行良好,但我想知道是否有更简洁的方法。我检查了Ruby文档,找不到任何内置方法,但我想对此进行输入。

5 个答案:

答案 0 :(得分:2)

由于Michael Kohl最近一直提醒group_by

articles = [
    ["A1", "title 1"],
    ["A1", "title 2"],
    ["A2", "title 3"]
]
page_to_titles = articles.group_by(&:first).each { |k,v| v.map!(&:last) }

在1.9.2和1.8.7中使用相同的内容。

答案 1 :(得分:1)

articles.inject(Hash.new) do |hash, (page, title)|
  h[page] ||= []
  h[page] << title
  h
end

答案 2 :(得分:1)

[a,b,c].inject(Hash.new{ |h,k| h[k] = [] }) { |res,(p,t)| res[p] << t; res }

或仅适用于红宝石1.9:

[a,b,c].each_with_object(Hash.new{ |h,k| h[k] = [] }) { |(p,t),res| res[p] << t }

答案 3 :(得分:0)

您可以更好地描述自己的行为,并使用警卫||=代替if。我会像这样重构它:

articles = []
articles << ["A1", "title 1"] 
articles << ["A1", "title 2"]
articles << ["A2", "title 3"]

PAGE = 0
TITLE = 1

def merge_articles(articles)
  res = {}
  articles.each do |a|
    res[a[PAGE]] ||= []
    res[a[PAGE]] << a[TITLE] 
  end
  res
end

hash = merge_articles(articles)

答案 4 :(得分:0)

这应该适用于Ruby 1.9:

articles.inject({}) do |hash, (page, title)|
  hash.tap do |h|
    h[page] ||= []
    h[page] << title
  end
end