2014-09-21 59 views
0

由值整理哈希散列我有一个哈希结构是这样的:红宝石

{"string1" => 
    {date1 => 1, 
    date2 => 21, 
    date3 => 9}, 
"string2" => 
    {date1 => 23, 
    date2 => 88, 
    date3 => 2}, 
"string3" => 
    {date1 => 0, 
    date2 => 0, 
    date3 => 5} 
} 

它告诉我:“这个字符串,在这一天,发生了很多次。”我想重新排序它:

{date1 => 
{"string1" => 1, 
    "string2" => 23}, 
date2 => 
{"string1" => 21, 
    "string2" => 88}, 
date3 => 
{"string1" => 9, 
    "string2" => 2, 
    "string3" => 5} 
} 

所以现在它告诉我:“在这个日期,这个字符串发生了这么多次”。有可能某些日期会有很多带有计数的字符串,而其他日期可能有0个带有计数的字符串。最后,在给定的日期发生的任何字符串应该出现在哈希中。

我敢肯定,有一个非常优雅的红宝石方式。请帮忙!

+0

的日期将如何有0字符串与计数?如果日期出现在原始嵌套散列中,它有一个关联的字符串(键),不是吗? – 2014-09-21 21:09:54

+0

不一定。这是来自第三方服务,您可以在其中提供日期范围并返回结果。因此,对于每个字符串,整个日期范围都包含在内,通常有很多0s – cheeseandpepper 2014-09-21 21:12:41

+0

你的意思是,当你有'{“string1”=> {date1 => 0}}'时,'string1'不应该出现在产生'date1'键?那么你怎么最终在你的示例中使用'date1 => {“string1”=> 0}'? – 2014-09-21 21:20:54

回答

1

我相信这是做你想做的。

h = {"string1" => {"date1" => 1, "date2" => 21, "date3" => 9}, 
    "string2" => {"date1" => 23, "date2" => 88, "date3" => 2}, 
    "string3" => {"date1" => 0, "date2" => 0, "date3" => 5}} 

h.each_with_object({}) { |(k,v),g| v.each { |d,vv| 
    (g[d] ||= {}).update({ k=>vv }) } } 
    #=> {"date1"=>{"string1"=>1, "string2"=>23, "string3"=>0}, 
    # "date2"=>{"string1"=>21, "string2"=>88, "string3"=>0}, 
    # "date3"=>{"string1"=>9, "string2"=>2, "string3"=>5}} 

如果你不想与零值的对,这样做第一:

h.each { |k,v| v.delete_if { |_,vv| vv.zero? } } 
    #=> {"string1"=>{"date1"=>1, "date2"=>21, "date3"=>9}, 
    # "string2"=>{"date1"=>23, "date2"=>88, "date3"=>2}, 
    # "string3"=>{"date3"=>5}} 

h.each_with_object({}) { |(k,v),g| v.each { |d,vv| 
    (g[d] ||= {}).update({ k=>vv }) } } 
    #=> {"date1"=>{"string1"=>1, "string2"=>23}, 
    # "date2"=>{"string1"=>21, "string2"=>88}, 
    # "date3"=>{"string1"=>9, "string2"=>2, "string3"=>5}} 

我做了datex的字符串。如果他们是Date对象(或符号等),表达式将没有什么不同。

+0

这个作品!谢谢! – cheeseandpepper 2014-09-21 22:21:25

+0

我结束了使用一个完整的块,并删除了0条目和空字符串的条目: 'hash.each_with_object({})do |(key,value),subhash | next if if ==“” value.each do | k,v |如果v> 0 结束 结束 ' – cheeseandpepper 2014-09-21 22:39:20

+0

@cheeseandpepper请注意,有了这个答案(或您的更新代码),你赢得了''''' t获得OP中所需的空日期('date6 => {}')。但是,现在对你来说可以。 – 2014-09-22 07:15:04

1

这里是另一种方式来做到这一点:

res = Hash.new { |h, k| h[k] = {} } 
hash.each do |kstring, datehash| 
    datehash.each { |kdate, n| n == 0 ? res[kdate] : res[kdate][kstring] = n } 
end 
+0

中的差异,但这更接近我的初始尝试 - 我想要使用初始值为0的新哈希值并重新计算计数值。很好地完成了这一点! – cheeseandpepper 2014-09-21 22:42:31