average 3.0 → 3.1
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +32 -2
- data/lib/average.rb +1 -2
- data/lib/average/array_overrides.rb +10 -2
- data/lib/average/average_helper.rb +35 -32
- data/lib/average/mean.rb +6 -4
- data/lib/average/median.rb +19 -17
- data/lib/average/mode.rb +30 -17
- data/lib/average/version.rb +2 -2
- data/spec/array_overrides_spec.rb +9 -1
- data/spec/average_helper_spec.rb +2 -2
- data/spec/mode_spec.rb +23 -12
- metadata +2 -2
data/README.md
CHANGED
@@ -1,6 +1,8 @@
|
|
1
|
+
[![Build Status](https://semaphoreci.com/api/v1/projects/fd96a25e-c843-44ff-8c43-1da486ca03a6/425376/badge.svg)](https://semaphoreci.com/fegoa89/average)
|
2
|
+
|
1
3
|
# Average
|
2
4
|
|
3
|
-
|
5
|
+
Simple gem to calculate mean, median and mode from an array.
|
4
6
|
|
5
7
|
## Installation
|
6
8
|
|
@@ -18,7 +20,35 @@ Or install it yourself as:
|
|
18
20
|
|
19
21
|
## Usage
|
20
22
|
|
21
|
-
|
23
|
+
Get Median
|
24
|
+
|
25
|
+
$ [3, 4, 5, 2, 3, 1].mean
|
26
|
+
$ 3.0
|
27
|
+
|
28
|
+
Get Mode
|
29
|
+
|
30
|
+
$ [2,4,6,14,21,24,229,24,24,39].mode
|
31
|
+
$ 24
|
32
|
+
|
33
|
+
It gives back an array due that could be possible to have more than one mode in a array
|
34
|
+
|
35
|
+
$ [1, 2, 2, 2, 3, 3, 7, 7, 7, 9].mode
|
36
|
+
$ [2, 7]
|
37
|
+
|
38
|
+
But if you want to have only a unique mode, you can use 'unique_mode' method (Only for Ruby versions bigger than 1.8.7 -> http://apidock.com/ruby/v1_8_7_72/Enumerable/max_by).
|
39
|
+
|
40
|
+
$ [1, 2, 2, 2, 3, 3, 7, 7, 7, 9].unique_mode
|
41
|
+
$ 2
|
42
|
+
|
43
|
+
Get Median
|
44
|
+
|
45
|
+
$ [3,4,5].median
|
46
|
+
$ 4
|
47
|
+
|
48
|
+
All methods described aboved can handle an array of integers, floats, strings or a mixed array with all of them
|
49
|
+
|
50
|
+
$ [3, "4", 5, 2.0, 3, "1.0"].mean
|
51
|
+
$ 3.0
|
22
52
|
|
23
53
|
## Contributing
|
24
54
|
|
data/lib/average.rb
CHANGED
@@ -1,5 +1,8 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
include Mean
|
2
|
+
include Mode
|
3
|
+
include Median
|
4
|
+
include AverageHelper
|
5
|
+
|
3
6
|
class Array
|
4
7
|
def mean
|
5
8
|
get_mean(self)
|
@@ -12,4 +15,9 @@ class Array
|
|
12
15
|
def median
|
13
16
|
get_median(self)
|
14
17
|
end
|
18
|
+
|
19
|
+
def unique_mode
|
20
|
+
get_unique_mode(self)
|
21
|
+
end
|
22
|
+
|
15
23
|
end
|
@@ -1,43 +1,46 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
1
|
+
module AverageHelper
|
2
|
+
def valid_array?(array)
|
3
|
+
# Valid if:
|
4
|
+
# - the class of the parameter 'array' respond to Array
|
5
|
+
# - the parameter 'Array' is not null or empty.
|
6
|
+
# - The array given contains Integers, Floats, and Strings that could be turned to a valid digit.
|
7
|
+
( array.is_a?(Array) && !array.nil? && !array.empty? && array_contain_digits?(array) )
|
8
|
+
end
|
8
9
|
|
9
|
-
def array_contain_digits?(array)
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
10
|
+
def array_contain_digits?(array)
|
11
|
+
# Go through all elements
|
12
|
+
result = true
|
13
|
+
array.each do |array_element|
|
14
|
+
if !value_can_be_handled?(array_element)
|
15
|
+
result = false
|
16
|
+
end
|
15
17
|
end
|
18
|
+
result
|
16
19
|
end
|
17
|
-
result
|
18
|
-
end
|
19
20
|
|
20
|
-
def value_can_be_handled?(element)
|
21
|
-
|
22
|
-
|
23
|
-
end
|
21
|
+
def value_can_be_handled?(element)
|
22
|
+
# Check if the elements of the array 'look like numbers'.
|
23
|
+
element.is_a?(Integer) || element.is_a?(Float) || looks_like_a_digit?(element)
|
24
|
+
end
|
24
25
|
|
25
26
|
|
26
|
-
def looks_like_a_digit?(digit)
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
27
|
+
def looks_like_a_digit?(digit)
|
28
|
+
if digit.is_a?(String) && digit !~ /^\s*[+-]?((\d+_?)*\d+(\.(\d+_?)*\d+)?|\.(\d+_?)*\d+)(\s*|([eE][+-]?(\d+_?)*\d+)\s*)$/
|
29
|
+
# is _not_ a string that could be turned to a digit
|
30
|
+
false
|
31
|
+
else
|
32
|
+
# is a string that could be a digit
|
33
|
+
true
|
34
|
+
end
|
33
35
|
end
|
34
|
-
end
|
35
36
|
|
36
|
-
def clean_array(array)
|
37
|
-
|
38
|
-
|
39
|
-
|
37
|
+
def clean_array(array)
|
38
|
+
array.each_with_index do |val, index|
|
39
|
+
if val.is_a?(String)
|
40
|
+
val.include?('.') ? (array[index] = val.to_f) : (array[index] = val.to_i)
|
41
|
+
end
|
40
42
|
end
|
43
|
+
array
|
41
44
|
end
|
42
|
-
|
45
|
+
|
43
46
|
end
|
data/lib/average/mean.rb
CHANGED
@@ -1,5 +1,7 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
1
|
+
module Mean
|
2
|
+
def get_mean(array)
|
3
|
+
if valid_array?(array)
|
4
|
+
clean_array(array).inject(0) { |sum, x| sum += x } / array.size.to_f
|
5
|
+
end
|
6
|
+
end
|
5
7
|
end
|
data/lib/average/median.rb
CHANGED
@@ -1,22 +1,24 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
end
|
1
|
+
module Median
|
2
|
+
def get_median(array)
|
3
|
+
if valid_array?(array)
|
4
|
+
calculate_median(clean_array(array))
|
5
|
+
end
|
6
|
+
end
|
6
7
|
|
7
|
-
def calculate_median(array)
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
8
|
+
def calculate_median(array)
|
9
|
+
array.sort!
|
10
|
+
if array.length.even?
|
11
|
+
get_mean( middle_items_to_average(array) )
|
12
|
+
else
|
13
|
+
array[ array.length / 2.to_f ]
|
14
|
+
end
|
13
15
|
end
|
14
|
-
end
|
15
16
|
|
16
|
-
def middle_item(array)
|
17
|
-
|
18
|
-
end
|
17
|
+
def middle_item(array)
|
18
|
+
array.size / 2
|
19
|
+
end
|
19
20
|
|
20
|
-
def middle_items_to_average(array)
|
21
|
-
|
21
|
+
def middle_items_to_average(array)
|
22
|
+
array[ middle_item(array) -1 .. middle_item(array) ]
|
23
|
+
end
|
22
24
|
end
|
data/lib/average/mode.rb
CHANGED
@@ -1,20 +1,33 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
1
|
+
module Mode
|
2
|
+
def get_mode(array)
|
3
|
+
if valid_array?(array)
|
4
|
+
result = repetition_hash( clean_array(array) )
|
5
|
+
if build_hash_result(result).count > 1
|
6
|
+
# It contains more than one mode
|
7
|
+
build_hash_result(result).keys.collect { |float| float.to_i }
|
8
|
+
else
|
9
|
+
# It contains only one mode
|
10
|
+
build_hash_result(result).keys.first
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
7
14
|
|
8
|
-
def repetition_hash(array)
|
9
|
-
|
10
|
-
|
11
|
-
result = array.inject({}) { |key, value| key[value] = array.count(value.to_f); key }
|
12
|
-
{ hash_result: result, max_repetition: result.values.max }
|
13
|
-
end
|
15
|
+
def repetition_hash(array)
|
16
|
+
{ hash_result: build_repetition_result(array), max_repetition: build_repetition_result(array).values.max }
|
17
|
+
end
|
14
18
|
|
15
|
-
def
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
19
|
+
def build_hash_result(result)
|
20
|
+
result[:hash_result].select { |key, value| value == result[:max_repetition] }
|
21
|
+
end
|
22
|
+
|
23
|
+
def build_repetition_result(array)
|
24
|
+
array.inject({}) { |key, value| key[value] = array.count(value.to_f); key }
|
25
|
+
end
|
26
|
+
|
27
|
+
def get_unique_mode(array)
|
28
|
+
# only for Ruby versions bigger than 1.8.7 -> http://apidock.com/ruby/v1_8_7_72/Enumerable/max_by
|
29
|
+
if valid_array?(array)
|
30
|
+
clean_array(array).max_by { |x| clean_array(array).count(x) }
|
31
|
+
end
|
32
|
+
end
|
20
33
|
end
|
data/lib/average/version.rb
CHANGED
@@ -1,3 +1,3 @@
|
|
1
|
-
|
2
|
-
VERSION = "3.
|
1
|
+
class Average
|
2
|
+
VERSION = "3.1"
|
3
3
|
end
|
@@ -2,7 +2,7 @@ require 'spec_helper'
|
|
2
2
|
|
3
3
|
describe Average do
|
4
4
|
|
5
|
-
let(:int_array) { [3,4,5]
|
5
|
+
let(:int_array) { [3,4,5] }
|
6
6
|
|
7
7
|
describe '.mean' do
|
8
8
|
context 'should give back the same result as' do
|
@@ -28,4 +28,12 @@ describe Average do
|
|
28
28
|
end
|
29
29
|
end
|
30
30
|
|
31
|
+
describe '.unique_mode' do
|
32
|
+
context 'should give back the same result as ' do
|
33
|
+
it 'get_unique_mode([X,X,X,X])' do
|
34
|
+
expect(int_array.unique_mode).to eq(get_unique_mode(int_array))
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
31
39
|
end
|
data/spec/average_helper_spec.rb
CHANGED
@@ -97,11 +97,11 @@ describe Average do
|
|
97
97
|
end
|
98
98
|
|
99
99
|
describe '#clean_array' do
|
100
|
-
context 'with an array that
|
100
|
+
context 'with an array that has a valid mixed-array structure' do
|
101
101
|
it 'should return an array without string and with the correct numeric format' do
|
102
102
|
expect(clean_array(valid_array)).to eq([3, 4.0, 5, 2, 0.3])
|
103
103
|
end
|
104
104
|
end
|
105
105
|
end
|
106
106
|
|
107
|
-
end
|
107
|
+
end
|
data/spec/mode_spec.rb
CHANGED
@@ -7,6 +7,8 @@ describe Average do
|
|
7
7
|
let(:mode_array) { [1,1,2,2,3,4] }
|
8
8
|
|
9
9
|
let(:mixed_array) { [3, 4.0, 5, 2.0, 3, 1.0] }
|
10
|
+
let(:array_with_two_modes) { [1, 2, 2, 2, 3, 3, 7, 7, 7, 9] }
|
11
|
+
let(:array_with_one_mode) { [2, 4, 6, 14, 21, 24, 229, 24, 24, 39] }
|
10
12
|
|
11
13
|
describe '#get_mode' do
|
12
14
|
|
@@ -17,36 +19,36 @@ describe Average do
|
|
17
19
|
end
|
18
20
|
|
19
21
|
context 'with a empty array' do
|
20
|
-
it 'should return
|
22
|
+
it 'should return nil' do
|
21
23
|
expect(get_mode([])).to eq(nil)
|
22
24
|
end
|
23
25
|
end
|
24
26
|
|
25
27
|
context 'with a nil object' do
|
26
|
-
it 'should return a
|
28
|
+
it 'should return a nil' do
|
27
29
|
expect(get_mode([])).to eq(nil)
|
28
30
|
end
|
29
31
|
end
|
30
32
|
|
31
33
|
end
|
32
34
|
|
33
|
-
describe '#
|
35
|
+
describe '#get_unique_mode' do
|
34
36
|
|
35
37
|
context 'with a array of integers' do
|
36
38
|
it 'should calculate the correct mode returning only one mode' do
|
37
|
-
expect(
|
39
|
+
expect(get_unique_mode(mode_array)).to eq(1)
|
38
40
|
end
|
39
41
|
end
|
40
42
|
|
41
43
|
context 'with a empty array' do
|
42
44
|
it 'should return nil' do
|
43
|
-
expect(
|
45
|
+
expect(get_unique_mode([])).to eq(nil)
|
44
46
|
end
|
45
47
|
end
|
46
48
|
|
47
49
|
context 'with a nil object' do
|
48
50
|
it 'should return nil' do
|
49
|
-
expect(
|
51
|
+
expect(get_unique_mode(nil)).to eq(nil)
|
50
52
|
end
|
51
53
|
end
|
52
54
|
|
@@ -71,17 +73,26 @@ describe Average do
|
|
71
73
|
end
|
72
74
|
|
73
75
|
context 'with a empty array' do
|
74
|
-
it 'should return
|
75
|
-
expect(repetition_hash([])).to eql(nil)
|
76
|
+
it 'should return a hash with empty values' do
|
77
|
+
expect(repetition_hash([])).to eql({:hash_result=>{}, :max_repetition=>nil})
|
76
78
|
end
|
77
79
|
end
|
78
80
|
|
79
|
-
|
80
|
-
|
81
|
-
|
81
|
+
end
|
82
|
+
|
83
|
+
describe 'testing returned values' do
|
84
|
+
|
85
|
+
context 'with an array that has two modes' do
|
86
|
+
it 'should return an array with two values' do
|
87
|
+
expect(get_mode(array_with_two_modes)).to eq([2, 7])
|
82
88
|
end
|
83
89
|
end
|
84
90
|
|
91
|
+
context 'with an array that has one modes' do
|
92
|
+
it 'should return an array with two values' do
|
93
|
+
expect(get_mode(array_with_one_mode)).to eq(24)
|
94
|
+
end
|
95
|
+
end
|
85
96
|
end
|
86
97
|
|
87
|
-
end
|
98
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: average
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: '3.
|
4
|
+
version: '3.1'
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2015-03
|
12
|
+
date: 2015-11-03 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: bundler
|