image by Ray Reyes

# Calculate the mode & median averages of a Ruby array

I’ve previously disscussed a way to calculate the mean of an array in Ruby. But there are two other averages that you might see, less commonly used, but still useful.

I'm co-chairing RailsConf 2024 in Detroit May 7–9.

Come and join us

## Calculate a median…

```
a = [1, 3, 2, 4, 6, 5, 7, 8]
sorted = a.sort # required
#=> [1, 2, 3, 4, 5, 6, 7, 8]
midpoint = a.length / 2 # integer division
#=> 4
if a.length.even?
# median is mean of two values around the midpoint
sorted[midpoint-1, 2].sum / 2.0
else
sorted[midpoint]
end
#=> 4.5
```

## Calculate a mode…

…using `Array#tally`

then sorting:

```
a = [1, 3, 3, 4, 6, 5, 7, 8]
tallied = a.tally
#=> {1=>1, 3=>2, 4=>1, 6=>1, 5=>1, 7=>1, 8=>1}
top_pair = tallied.sort_by { |_,v| v }.last(2)
#=> [[8, 1], [3, 2]]
if top_pair.size == 1
top_pair[0][0] # only one element, it is the mode
elsif top_pair[0][1] == top_pair[1][1]
nil # if count is same, no mode.
else
top_pair[1][0]
end
#=> 3
```

## Why?

The `#tally`

method was added to `Enumerable`

in Ruby 2.7 so you might see implementations that use `inject`

, which will perform worse.

I compared the performance of using native Ruby methods versus your own implementations when I wrote about calculating the mean.

## Anything else?

It’s no doubt a good idea to further encapsulate these calulations into methods.

If you’re doing a lot of this sort of calculation or in a situation where performance is important you should look at the `enumerable-statistics`

gem. It has natively implemented versions of several statistical summary methods mixed into `Array`

and `Enumerable`

.

The implementation in C means these methods are much faster than any version of the algorithm programmed in Ruby.

Still running UK’s friendliest, Ruby event on Friday 28th June.

Ice cream + Ruby

Last updated on June 21st, 2021 by @andycroll

An email newsletter, with one Ruby/Rails technique delivered with a ‘why?’ and a ‘how?’ every two weeks. It’s deliberately brief, focussed & opinionated.