Ruby - 按组排序哈希数组

时间:2014-04-06 22:19:33

标签: ruby hash grouping

data = [{'id' => 1, 'num' => 10},
        {'id' => 1, 'num' => 5},
        {'id' => 1, 'num' => 8},
        {'id' => 2, 'num' => 0},
        {'id' => 2, 'num' => 20},
        {'id' => 2, 'num' => -5},
        {'id' => 5, 'num' => 9},
        {'id' => 5, 'num' => 9}]

我想根据与每个id组相关联的最大num,按相同id的群组订购此信息。然后在每个组中,num也可用于进一步排序。

data_transformed = 
            [{'id' => 2, 'num' => 20},
            {'id' => 2, 'num' => 0},
            {'id' => 2, 'num' => -5},
            {'id' => 1, 'num' => 10},
            {'id' => 1, 'num' => 8},
            {'id' => 1, 'num' => 5},
            {'id' => 5, 'num' => 9},
            {'id' => 5, 'num' => 9}]

这也没关系

data_transformed = 
            [[{'id' => 2, 'num' => 20},
            {'id' => 2, 'num' => 0},
            {'id' => 2, 'num' => -5}],

            [{'id' => 1, 'num' => 10},
            {'id' => 1, 'num' => 8},
            {'id' => 1, 'num' => 5}],

            [{'id' => 5, 'num' => 9},
            {'id' => 5, 'num' => 9}]]

我该怎么做?

3 个答案:

答案 0 :(得分:2)

我做:

data = [{'id' => 1, 'num' => 10},
        {'id' => 1, 'num' => 5},
        {'id' => 1, 'num' => 8},
        {'id' => 2, 'num' => 0},
        {'id' => 2, 'num' => 20},
        {'id' => 2, 'num' => -5},
        {'id' => 5, 'num' => 9},
        {'id' => 5, 'num' => 9}]

data_grouped_ordered_by_num = data.group_by { |h| h['id'] }.sort_by { |_,v| v.map { |h| h['num'] }.max }.reverse
# => [[2, [{"id"=>2, "num"=>0}, {"id"=>2, "num"=>20}, {"id"=>2, "num"=>-5}]],
#     [1, [{"id"=>1, "num"=>10}, {"id"=>1, "num"=>5}, {"id"=>1, "num"=>8}]],
#     [5, [{"id"=>5, "num"=>9}, {"id"=>5, "num"=>9}]]]

data_grouped_ordered_by_num.map { |k,v| v.sort_by {|h| -h['num']} }
# => [[{"id"=>2, "num"=>20}, {"id"=>2, "num"=>0}, {"id"=>2, "num"=>-5}],
#     [{"id"=>1, "num"=>10}, {"id"=>1, "num"=>8}, {"id"=>1, "num"=>5}],
#     [{"id"=>5, "num"=>9}, {"id"=>5, "num"=>9}]]

答案 1 :(得分:1)

data.group_by{ |x| x['id'] }.values.map do |x|
  x.sort_by do |y| 
    -y['num']
  end 
end

#=> [[{"id"=>1, "num"=>10}, {"id"=>1, "num"=>8}, {"id"=>1, "num"=>5}],
 [{"id"=>2, "num"=>20}, {"id"=>2, "num"=>0}, {"id"=>2, "num"=>-5}],  
 [{"id"=>5, "num"=>9}, {"id"=>5, "num"=>9}]]

之后您可以使用flatten来平衡结果,这将为您提供第一个所需的输出:

[{"id"=>1, "num"=>10},
 {"id"=>1, "num"=>8},
 {"id"=>1, "num"=>5},
 {"id"=>2, "num"=>20},
 {"id"=>2, "num"=>0},
 {"id"=>2, "num"=>-5},
 {"id"=>5, "num"=>9},
 {"id"=>5, "num"=>9}]

答案 2 :(得分:1)

data.sort_by { |h| [h['id'], -h['num']] } 
  #=> [{'id' => 1, 'num'=>10}, {'id'=>1, 'num'=>8}, {'id'=>1, 'num'=> 5},
  #    {'id' => 2, 'num'=>20}, {'id'=>2, 'num'=>0}, {'id'=>2, 'num'=>-5},
  #    {'id' => 5, 'num'=> 9}, {'id'=>5, 'num'=>9}]

对于第二种格式:

data.sort_by { |h| [h['id'], -h['num']] }.chunk { |h| h['id'] }.map(&:last)
  #=> [[{"id"=>1, "num"=>10}, {"id"=>1, "num"=>8}, {"id"=>1, "num"=> 5}],
  #    [{"id"=>2, "num"=>20}, {"id"=>2, "num"=>0}, {"id"=>2, "num"=>-5}],
  #    [{"id"=>5, "num"=> 9}, {"id"=>5, "num"=>9}]]

Array#sort_by使用Array#<=>进行比较。后者的文档解释了为什么这会产生预期的结果。