Last active
May 20, 2021 10:55
-
-
Save mudge/a653a1fb837e108a5501937c456f4412 to your computer and use it in GitHub Desktop.
A Ruby refinement to add methods to Enumerable for calculating the three Pythagorean means.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# A refinement to add methods to Enumerables for calculating the three | |
# Pythagorean means. | |
# | |
# See https://en.wikipedia.org/wiki/Pythagorean_means | |
module PythagoreanMeans | |
# Note that due to a bug refining modules in Ruby 2.7 [1], we can't `refine | |
# Enumerable` so we `refine Array` instead. | |
# | |
# See also https://interblah.net/why-is-nobody-using-refinements | |
# | |
# [1]: https://bugs.ruby-lang.org/issues/16852 | |
refine Array do | |
def arithmetic_mean | |
(1.0 / length) * sum | |
end | |
alias_method :mean, :arithmetic_mean | |
alias_method :average, :arithmetic_mean | |
def geometric_mean | |
inject(:*)**(1.0 / length) | |
end | |
def harmonic_mean | |
Float(length) / sum { |x| 1.0 / x } | |
end | |
end | |
end | |
RSpec.describe PythagoreanMeans do | |
using PythagoreanMeans | |
describe '#arithmetic_mean' do | |
it 'returns the arithmetic mean of an array' do | |
expect([1, 2, 3, 4, 5].arithmetic_mean).to eq(3) | |
end | |
it 'is the greatest of the three means' do | |
xs = [1, 2, 3, 4, 5] | |
_least, _middle, greatest = | |
[xs.arithmetic_mean, xs.geometric_mean, xs.harmonic_mean].sort | |
expect(greatest).to eq(xs.arithmetic_mean) | |
end | |
end | |
describe '#mean' do | |
it 'is an alias for the arithmetic mean' do | |
expect([1, 2, 3, 4, 5].mean).to eq(3) | |
end | |
end | |
describe '#average' do | |
it 'is an alias for the arithmetic mean' do | |
expect([1, 2, 3, 4, 5].average).to eq(3) | |
end | |
end | |
describe '#geometric_mean' do | |
it 'returns the geometric mean of an array' do | |
expect([1, 2, 3, 4, 5].geometric_mean).to be_within(0.01).of(2.61) | |
end | |
it 'is in the middle of the three means' do | |
xs = [1, 2, 3, 4, 5] | |
_least, middle, _greatest = | |
[xs.arithmetic_mean, xs.geometric_mean, xs.harmonic_mean].sort | |
expect(middle).to eq(xs.geometric_mean) | |
end | |
end | |
describe '#harmonic_mean' do | |
it 'returns the harmonic mean of an array' do | |
expect([1, 2, 3, 4, 5].harmonic_mean).to be_within(0.01).of(2.18) | |
end | |
it 'is the least of the three means' do | |
xs = [1, 2, 3, 4, 5] | |
least, _middle, _greatest = | |
[xs.arithmetic_mean, xs.geometric_mean, xs.harmonic_mean].sort | |
expect(least).to eq(xs.harmonic_mean) | |
end | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment