Domanda

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?

È stato utile?

Soluzione

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

Altri suggerimenti

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.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top