2012-01-21 59 views
0

如果我有散列的数组,每一个天键:如何将散列数组转换为排序哈希?

[ 
    {:day=>4,:name=>'Jay'}, 
    {:day=>1,:name=>'Ben'}, 
    {:day=>4,:name=>'Jill'} 
] 

什么是将其转换为与排序的日期值的哈希作为密钥的最佳途径:

{ 
    :1=>[{:day=>1,:name=>'Ben'}], 
    :4=>[{:day=>4,:name=>'Jay'},{:day=>4,:name=>'Jill'}] 
} 

我“M使用Ruby 1.9.2和Rails 3.1.1

+0

Hash本质上不排序。 Ruby 1.9+维护插入顺序,所以如果你创建一个散列并且根据排序顺序插入元素,Ruby将会维护这些元素。但是,任何后续元素都不会被排序,而会被添加。如果您需要按特定顺序检索它们,则可以在检索值之前对键进行排序,或者可以将键阵列与散列并行维护,然后按照所需顺序保存该阵列,然后迭代该数组,或者将其与'values_at'一起使用,以按照您想要的顺序检索值。 –

回答

4

个人而言,我不会打扰“排序”键(这等于在Ruby 1.9中按输入时间排序),直到我真正需要。当你真正需要它们

arr = [{:day=>4,:name=>'Jay'}, {:day=>1,:name=>'Ben'}, {:day=>4,:name=>'Jill'}] 
arr.group_by { |a| a[:day] } 
=> {4=>[{:day=>4, :name=>"Jay"}, {:day=>4, :name=>"Jill"}], 
    1=>[{:day=>1, :name=>"Ben"}]} 

相反,排序键:然后你就可以使用group_by

+0

+1这真棒。 – Anurag

1

假设你数组被称为是list,这里是一个使用reduce方法的一种方法:

list.reduce({}) { |hash, item| 
    (hash[item[:day]] ||= []) << item; hash 
} 

这里的另一个使用map方法,但你必须随身携带的支架变量:

hash = {} 
list.each { |item| 
    (hash[item[:day]] ||= []) << item 
} 

一旦你的无序哈希说,在可变foo,你可以对它进行排序的,

Hash[foo.sort] 
+0

如果你要放弃结果,你不应该使用'map'。改为使用'each'! –

+0

@VictorMoroz - 感谢您指出。我添加了更改。 – Anurag

0

答案很简单:

data = [ 
    {:day=>4,:name=>'Jay'}, 
    {:day=>1,:name=>'Ben'}, 
    {:day=>4,:name=>'Jill'} 
] 

#expected solution 
sol = { 
    1=>[{:day=>1,:name=>'Ben'}], 
    4=>[{:day=>4,:name=>'Jay'},{:day=>4,:name=>'Jill'}] 
} 

res = {} 
data.each{|h| 
    res[h[:day]] ||= [] 
    res[h[:day]] << h 
} 

p res 
p res == sol #check value 
p res.keys == sol.keys #check order 

问题与此解决方案:按要求哈希值进行排序。 (同样的问题有Anurags solution)。

所以你必须修改回答一下:

res = {} 
data.sort_by{|h| h[:day]}.each{|h| 
    res[h[:day]] ||= [] 
    res[h[:day]] << h 
} 

p res 
p res == sol #check value 
p res.keys == sol.keys #check order 
0

在Rails中,你可以使用OrderedHash

ActiveSupport::OrderedHash[arr.group_by { |a| a[:day] }.sort_by(&:first)] 

更新:事实上,在Ruby 1.9的散列是有序的,所以使用ActiveSupport不需要扩展名:

Hash[arr.group_by { |a| a[:day] }.sort_by(&:first)]