2011-09-03 40 views
1

我正在研究一个项目,我需要将报纸文章与它们在印刷品上出现的页码相关联。帮助重新分解Ruby散列切片和切块

我的输入数据只是一堆成对的文章标题和页码。我想出了下面的代码创建一个新的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文档并找不到任何内置方法,但我希望SO对此有所贡献。

回答

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
articles.inject(Hash.new) do |hash, (page, title)| 
    h[page] ||= [] 
    h[page] << title 
    h 
end 
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) 
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 } 
0

这应该在Ruby 1.9的工作:

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