0

I have an array of instances of model Foo. Foo is an Ohm based data store. Each instance of Foo has an_id and integer attributes such as follows, likes. If there are two instances of Foo with the same an_id, I'd love to add the follows and likes attributes together. The solution I had was to create a hash where each key is an an_id of the array, and keep the state there. If the array is large enough, this is not efficient as I need each object back into an array. I'd love to group the array by Foo#an_id and merge/add the counter attributes together and pop that back into the array. Is something like this currently supported?

sawa
  • 165,429
  • 45
  • 277
  • 381
randombits
  • 47,058
  • 76
  • 251
  • 433

2 Answers2

1

group_by, sum

As a start, something like this:

grouped_hash = your_array.group_by(&:an_id)
sums_by_id = {}
grouped_hash.each do |id,values|
  sums_by_id[id] = {}
  # you could also just iterate over values once and += :follows and :likes
  sums_by_id[id][:follows] = values.sum(&:follows)
  sums_by_id[id][:likes]   = values.sum(&:likes)
end

Example output: sums_by_id => {1 => {:follows => 2, :likes => 4}, 2 => ...

Additionally, take a look at:

inject

(5..10).inject {|sum, n| sum + n }  # 45
Matt Dressel
  • 2,194
  • 16
  • 18
  • I think the problem with the solution above is I need this back into an array so I can perform a sort operation. Ideally I'd like to sort by follows/likes etc. Is there a trivial way to do so using the data structure you built above? – randombits Feb 25 '13 at 04:32
  • sums_by_id.to_a.sort_by {| obj | block } → array – Matt Dressel Feb 25 '13 at 04:45
  • You might want to consider doing this in the database. Model.where(:some_id_attr => an_id).all.order('follows DESC'), or use active record :group and :sum – Matt Dressel Feb 25 '13 at 04:58
0

You can use inject to get a sum of values:

array = *array of Foo*
total = array.inject { |sum, x| sum + x.likes }
Richard Brown
  • 11,346
  • 4
  • 32
  • 43