Reputation: 83
I am writing a method that takes an array and returns another array of the averages of each number and the next number in the array.
I tried using map
but have been staring at it too long and can't see where I'm going wrong:
array = [ 1, 3, 5, 1, -10]
array.map! { |a| (a + arr[a+1])/2 }
I expect:
[ 2, 4, 3, -4.5]
Upvotes: 0
Views: 110
Reputation: 575
Edit: the key takeaway to follow is that you are indexing your array with the an array value, not an index.
There's lots of available one line answers to your question so I'll try to address your code:
array.map! { |a| (a + arr[a + 1]) / 2 }
The key thing to understand with map
is that it acts on an array and returns an array (you used map!
which is in place, but we can disregard that for now. You can't get the average with map because it returns an array.
Ex:
[1, 2, 3, 4].map { |num| num * num } # returns [1, 4, 9, 16]
So let's walk through your code and see what it is doing:
[1, 2, 3].map { |a| (a + arr[a + 1]) / 2 }
The first call to |a| (a + arr[a + 1]) / 2
, a
will be 1. So the first element of your returned array is 1 + arr[1 + 1] / 2 = 1 + 3 / 2 ~= 2
And so on. Clearly this isn't what you want.
Now for the one line solutions (I took this from here):
arr.inject { |sum, el| sum + el }.to_f / arr.size
inject
is the same as reduce
, which is foldr
in some languages. This is a bit more complicated than map
. Basically the method |sum, el| sum + el
is applied to the first two elements, and the result of that is applied to the third element and so on until the end of the array.
So if our array is [1, 2, 3, 4]
, a arithmetic call stack might look something like this:
((1 + 2) + 3) + 4
With these two methods, you should be able to accomplish what you need, i.e. an array of averages. Or at the very least this should help you understand the other solutions.
Upvotes: 2
Reputation: 52347
You can use Enumerable#each_cons
:
array = [ 1, 3, 5, 1, -10]
array.each_cons(2).map { |a| a.inject(:+) / 2.0 }
#=> [2.0, 4.0, 3.0, -4.5]
Summarizing it into a method:
def each_cost_avg(array, size = 2)
array.each_cons(size).map { |a| a.inject(:+) / size.to_f }
end
each_cost_avg(array, 2) #=> [2.0, 4.0, 3.0, -4.5]
each_cost_avg(array, 3) #=> [3.0, 3.0, -1.3333333333333333]
each_cost_avg(array, 4) #=> [2.5, -0.25]
Upvotes: 2