How to Condense Summable Metrics to a Unique Identifier in a Ruby Table

How to condense summable metrics to a unique identifier in a ruby table

I think the other answerers are overthinking this. You can do this with just one operation, each_with_object, and a Hash:

metrics = [["id1", 123], ["id2", 234], ["id1", 345]]

metrics.each_with_object(Hash.new(0)) do |(id, val), sums|
sums[id] += val
end
# => {"id1"=>468, "id2"=>234}

If you want an Array instead of a Hash at the end just call to_a on the result, but there are few compelling reasons to do so.

How to sum multiple elements of nested arrays on unique keys

This is essentially the same as the solution to your previous question.

data = [ [ 123.0, 23, "id1", 34, "abc" ], 
[ 234.1, 43, "id2", 24, "jsk" ],
[ 423.5, 53, "id1", 1, "xyz" ],
[ 1.4, 5, "id2", 0, "klm" ] ]

sums = Hash.new {|h,k| h[k] = [0, 0, 0] }

data.each_with_object(sums) do |(val0, val1, id, val2, _), sums|
sums[id][0] += val0
sums[id][1] += val1
sums[id][2] += val2
end
# => { "id1" => [ 546.5, 76, 35 ],
# "id2" => [ 235.5, 48, 24 ] }

The main difference is that instead of giving the Hash a default value of 0, we're giving it a default proc that initializes missing keys with [0, 0, 0]. (We can't just do Hash.new([0, 0, 0]) because then every value would be a reference to a single Array instance, rather than each value having its own Array.) Then, inside the block, we add each value (val0 et al) to the corresponding elements of sums[id].

If you wanted an Array of Arrays instead of a Hash with the id at index 2, then at the end, you would have to add something like this:

.map {|id, vals| vals.insert(2, id) }

However, a Hash with the ids as keys makes more sense as a data structure.



Related Topics



Leave a reply



Submit