문제

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}]

I want to order this information by groups of the same id according to the max num associated with each group of id. Then within each group, the num can also be used for further ordering.

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}]

This would also be fine

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}]]

How can I do this?

도움이 되었습니까?

해결책

I'd do :

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}]]

다른 팁

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}]]

You can use flatten after that to flat the result which will give you your first desired output:

[{"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']] } 
  #=> [{'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}]

For the second format:

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 uses Array#<=> for comparisons. Documentation for the latter explains why this produces the desired result.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top