How to find the maximum value grouped by several keys in a hash array?

Have data that has this structure. It will be in ascending order by 'c'.

[ { 'a' => 1, 'b' => 1, 'c' => 1, 'd' => '?' }, { 'a' => 1, 'b' => 1, 'c' => 2, 'd' => '?' }, { 'a' => 1, 'b' => 1, 'c' => 3, 'd' => '?' }, { 'a' => 1, 'b' => 2, 'c' => 4, 'd' => '?' }, { 'a' => 1, 'b' => 2, 'c' => 5, 'd' => '?' }, { 'a' => 2, 'b' => 1, 'c' => 6, 'd' => '?' }, { 'a' => 2, 'b' => 1, 'c' => 7, 'd' => '?' }, { 'a' => 2, 'b' => 1, 'c' => 8, 'd' => '?' }, { 'a' => 2, 'b' => 2, 'c' => 9, 'd' => '?' }, { 'a' => 2, 'b' => 2, 'c' => 10, 'd' => '?' } ] 

You want an array of maximum value 'c', grouped by each unique combination of 'a' and 'b'.

 [ { 'a' => 1, 'b' => 1, 'c' => 3, 'd' => '?' }, { 'a' => 1, 'b' => 2, 'c' => 5, 'd' => '?' }, { 'a' => 2, 'b' => 1, 'c' => 8, 'd' => '?' }, { 'a' => 2, 'b' => 2, 'c' => 10, 'd' => '?' } ] 

Other keys must be kept, but not associated with the conversion. The best that I could guess so far is to reverse the array (thus sorting in order of 'c'), uniq to 'a' an 'b' and again the reverse array. But depending on the uniq_by implementation, I always return the first unique element found. The spec doesn't talk about this, so I'm worried about relying on this behavior, as it may change in future versions. It is also interesting if this can be a really inefficient method.

 @data.reverse!.uniq!{|record| [record['a'],record['b']]}.reverse! 

Is there a better and effective way to do this? If you have a better way, can you also explain this, instead of just giving me a super-nasty single-line font that I might not be able to decrypt.

+4
source share
1 answer

This is actually pretty easy:

 a.group_by { |h| h.values_at("a", "b") }.map { |_, v| v.max_by { |h| h["c"] } } 

Or with better formatting:

 a.group_by do |h| h.values_at("a", "b") end.map do |_, v| v.max_by { |h| h["c"] } end 

Explanation: First, we use Enumerable # group_by to create a Hash with the combinations "a" and "b" (extracted using Hash # values_at ) as keys and all hashes with this combination as values. Then we map this hash, ignore the keys, and select the element with the maximum value for "c" from the array with Enumerable # max_by .

+10
source

Source: https://habr.com/ru/post/1412812/


All Articles