问题
Have data that has this kind of structure. 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' => '?' } ]
Want array of the max value of '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' => '?' } ]
The other keys need to be retained but are not otherwise related to the transformation. The best I could figure out so far is to reverse the array (thus descending ordered by 'c'), uniq by 'a' an 'b', and reverse array again. But I am depending on the implementation of uniq_by always returning the first unique item found. The specification doesn't say that, so I am worried about relying on that behavior since it could change in future versions. Also wondering if this may be a really inefficient method.
@data.reverse!.uniq!{|record| [record['a'],record['b']]}.reverse!
Is there a better and more efficient way to do this? If you do have a better way, can you also please explain it instead of just giving me a super nasty one-liner that I may not be able to decipher.
回答1:
That's actually fairly easy:
a.group_by { |h| h.values_at("a", "b") }.map { |_, v| v.max_by { |h| h["c"] } }
Or with nicer 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 of "a"
and "b"
(extracted with Hash#values_at) as the keys and all hashes with that combination as the values. We then map over this hash, ignore the keys and select the element with the maximum value for "c"
from the array with Enumerable#max_by.
来源:https://stackoverflow.com/questions/10621721/how-to-find-max-value-grouped-by-multiple-keys-in-array-of-hashes