This page contains automated test results for code from O'Reilly's Ruby Cookbook. If this code looks interesting or useful, you might want to buy the whole book.

Taking Mean, Median, and Mode
CodeExpectedActual
def mean(array)
  array.inject(0) { |sum, x| sum += x } / array.size.to_f
end
mean([1,2,3,4])
2.5 2.5
mean([100,100,100,100.1])
100.025 100.025
mean([-100, 100])
0.0 0.0
mean([3,3,3,3])
3.0 3.0
def median(array, already_sorted=false)
  return nil if array.empty?
  array = array.sort unless already_sorted
  m_pos = array.size / 2
  return array.size % 2 == 1 ? array[m_pos] : mean(array[m_pos-1..m_pos])
end
median([1,2,3,4,5])
3 3
median([5,3,2,1,4])
3 3
median([1,2,3,4])
2.5 2.5
median([1,1,2,3,4])
2 2
median([2,3,-100,100])
2.5 2.5
median([1, 1, 10, 100, 1000])
10 10
def modes(array, find_all=true)
  histogram = array.inject(Hash.new(0)) { |h, n| h[n] += 1; h }
  modes = nil
  histogram.each_pair do |item, times| 
    modes << item if modes && times == modes[0] and find_all
    modes = [times, item] if (!modes && times>1) or (modes && times>modes[0])
  end
  return modes ? modes[1...modes.size] : modes
end
modes([1,2,3,4])
nil nil
modes([1,1,2,3,4])
[1] [1]
modes([1,1,2,2,3,4])
[1, 2] [1, 2]
modes([1,1,2,2,3,4,4])
[1, 2, 4] [1, 2, 4]
modes([1,1,2,2,3,4,4], false)
[1] [1]
modes([1,1,2,2,3,4,4,4,4,4])
[4] [4]
def mean_without_float_conversion(array)
  array.inject(0) { |x, sum| sum += x } / array.size
end
require 'rational'
numbers = [Rational(2,3), Rational(3,4), Rational(6,7)]
mean(numbers)
0.757936507936508 0.757936507936508
mean_without_float_conversion(numbers)
Rational(191, 252) Rational(191, 252)
mean([1, 100, 100000])
33367.0 33367.0
median([1, 100, 100000])
100 100
mean([1, 100, -1000000])
-333299.666666667 -333299.666666667
median([1, 100, -1000000])
1 1
median(["a", "z", "b", "l", "m", "j", "b"])
"j" "j"
median(["a", "b", "c", "d"])
TypeError: String can't be coerced into Fixnum
...
TypeError: String can't be coerced into Fixnum
	from (irb):2:in `+'
	from (irb):2:in `mean'
	from (irb):47:in `inject'
	from (irb):2:in `mean'
	from (irb):12:in `median'
	from (irb):47
def mean_and_standard_deviation(array)
  m = mean(array)
  variance = array.inject(0) { |variance, x| variance += (x - m) ** 2 }
  return m, Math.sqrt(variance/(array.size-1))
end
#All the items in the list are close to the mean, so the standard
#deviation is low.
mean_and_standard_deviation([1,2,3,1,1,2,1])
[1.57142857142857, 0.786795792469443] [1.57142857142857, 0.786795792469443]
#The outlier increases the mean, but also increases the standard deviation.
mean_and_standard_deviation([1,2,3,1,1,2,1000])
[144.285714285714, 377.33526837801] [144.285714285714, 377.33526837801]