Reputation: 189
I'm working with multiple Arrays each with one string and many integers. I have managed to set together duplicates in nested arrays as I want to combine them. So as I loop over my parent array it outputs this:
[["word", 1, 1, 3, 4], ["word", 2, 1, 3, 4]]
and another example:
[["without", 1, 1, 3, 4], ["without", 2, 1, 3, 4], ["without", 3, 1, 0, 0]]
I want a function to combine these into one array and sum the integers. So the first example above would become:
["word", 3, 2, 6, 8]
I have tried many different techniques like inject and reduce. My latest attempt isn't the most elegant:
# data is set of array
def inject_array(data)
clicks = 0
imps = 0
cost = 0
converted_clicks = 0
data.each do |i|
clicks += i[1]
i[1] = clicks
imps += i[2]
i[2] = imps
cost += i[3]
i[3] = cost
converted_clicks += i[4]
i[4] = converted_clicks
end
It's getting a bit messy, is there a cleaner way?
Upvotes: 2
Views: 68
Reputation: 2617
One way is to loop over the arrays, sum the parts, and rebuild.
word_array = [['word', 1, 1, 3, 4], ['word', 2, 1, 3, 4]]
puts "Squashing #{word_array}..."
i1 = 0
i2 = 0
i3 = 0
i4 = 0
word_array.each do |arr|
i1 += arr[1]
i2 += arr[2]
i3 += arr[3]
i4 += arr[4]
end
puts ['word', i1, i2, i3, i4].inspect
Upvotes: 0
Reputation: 110675
You can also methods of the class Matrix. Recall that to sum each column of a matrix with r
rows, you pre-multiply the matrix by a row vector comprised of r
1
s:
require 'matrix'
a = [["word", 1, 1, 3, 4], ["word", 2, 1, 3, 4]]
[a.first.first, (Matrix[[1]*a.size] * Matrix[*a.map { |e| e[1..-1] }]).to_a.first]
#=> ["word", [3, 2, 6, 8]]
Upvotes: 0
Reputation: 62648
Assuming that the arrays will always be the same length, you can use Array#transpose
to transpose your array of arrays from row-based to column-based arrays:
[["word", 1, 1, 3, 4], ["word", 2, 1, 3, 4]].transpose
=> [["word", "word"], [1, 2], [1, 1], [3, 3], [4, 4]]
From there, it's trivial enough to sum the numbers in each:
[["word", 1, 1, 3, 4], ["word", 2, 1, 3, 4]].transpose.map.with_index do |e, i|
i == 0 ? e.first : e.inject(:+)
end # => ["word", 3, 2, 6, 8]
Upvotes: 4