views:

2359

answers:

6

How would get find an average from an array?

Say

[0,4,8,2,5,0,2,6]

would give 3.375

Thanks!

A: 

Don't have ruby on this pc, but something to this extent should work:

values = [0,4,8,2,5,0,2,6]
total = 0.0
values.each do |val|
 total += val
end

average = total/values.size
saret
+23  A: 

Try this:

arr = [5, 6, 7, 8]
arr.inject{ |sum, el| sum + el }.to_f / arr.size
=> 6.5

Note the .to_f, which you'll want for avoiding any problems from integer division. You can also do:

arr = [5, 6, 7, 8]
arr.inject(0.0) { |sum, el| sum + el } / arr.size
=> 6.5

You can define it as part of Array as another commenter has suggested, but you need to avoid integer division or your results will be wrong. Also, this isn't generally applicable to every possible element type (obviously, an average only makes sense for things that can be averaged). But if you want to go that route, use this:

  class Array
    def sum
      inject(0.0) { |result, el| result + el }
    end

    def mean 
      sum / size
    end
  end

If you haven't seen inject before, it's not as magical as it might appear. It iterates over each element and then applies an accumulator value to it. The accumulator is then handed to the next element. In this case, our accumulator is simply an integer that reflects the sum of all the previous elements.

Edit: Commenter Dave Ray proposed a nice improvement.

Edit: Commenter Glenn Jackman's proposal, using arr.inject(:+).to_f, is nice too but perhaps a bit too clever if you don't know what's going on. The :+ is a symbol; when passed to inject, it applies the method named by the symbol (in this case, the addition operation) to each element against the accumulator value.

John Feminella
You can eliminate to_f and ? operator by passing an initial value to inject: `arr.inject(0.0) { |sum,el| sum + el } / arr.size`.
Dave Ray
Or: arr.inject(:+).to_f / arr.size # => 3.375
glenn jackman
@glenn: That's nice too, but I think the Symbol#to_proc automatic conversion is just a bit too clever for a StackOverflow answer.
John Feminella
I don't think this warrants adding to the Array class, since it's not generalizable to all the types that Arrays can contain.
Sarah Mei
Chuck
@Chuck: Whoops, you're right; I missed that.
John Feminella
A: 
a = [0,4,8,2,5,0,2,6]
sum = 0
a.each { |b| sum += b }
average = sum / a.length
erik
This will return incorrect values because of integer division. For example, if a is [2, 3], the expected result is 2.5, but you'll return 2.
John Feminella
Thanks, that's why I voted your answer up
erik
A: 
 class Array
    def sum 
      inject( nil ) { |sum,x| sum ? sum+x : x }
    end

    def mean 
      sum.to_f / size.to_f
    end

  end

[0,4,8,2,5,0,2,6].mean

astropanic
This returns incorrect values because of integer division. Try it with, for example, [2,3].mean, which returns 2 instead of 2.5.
John Feminella
Needs more floatyness.
Andy Gaskell
+5  A: 
a = [0,4,8,2,5,0,2,6]
a.instance_eval { reduce(:+) / size.to_f } #=> 3.375
Corban Brook
A: 

I was hoping for Math.average(values), but no such luck.

values = [0,4,8,2,5,0,2,6] average = values.sum / values.size.to_f

Denny Abraham