simple_stats 1.0.0 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.travis.yml +3 -3
- data/Gemfile +3 -1
- data/README.md +26 -2
- data/Rakefile +9 -0
- data/lib/simple_stats/core_ext/enumerable.rb +71 -45
- data/lib/simple_stats/version.rb +1 -1
- data/spec/enumerable/frequencies_spec.rb +11 -1
- data/spec/enumerable/mean_spec.rb +6 -0
- data/spec/enumerable/median_spec.rb +6 -0
- data/spec/enumerable/modes_spec.rb +6 -0
- data/spec/enumerable/sorted_frequencies_spec.rb +6 -0
- data/spec/enumerable/sum_spec.rb +6 -0
- metadata +5 -5
data/.travis.yml
CHANGED
@@ -3,9 +3,9 @@ rvm:
|
|
3
3
|
- 1.8.7
|
4
4
|
- 1.9.2
|
5
5
|
- 1.9.3
|
6
|
+
- 2.0.0
|
6
7
|
- jruby-18mode # JRuby in 1.8 mode
|
7
8
|
- jruby-19mode # JRuby in 1.9 mode
|
8
|
-
- rbx
|
9
|
-
- rbx-19mode # currently in active development, may or may not work for your project
|
9
|
+
- rbx
|
10
10
|
# uncomment this line if your project needs to run something other than `rake`:
|
11
|
-
script: bundle exec rspec spec
|
11
|
+
# script: bundle exec rspec spec
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -77,7 +77,7 @@ samples.sorted_frequencies
|
|
77
77
|
[].frequencies # {}
|
78
78
|
[].sorted_frequencies # []
|
79
79
|
|
80
|
-
# if elements are
|
80
|
+
# if elements are present, mean and median always return floats
|
81
81
|
[1, 2, 3].mean # 2.0
|
82
82
|
[1, 2, 3].median # 2.0
|
83
83
|
[1, 2, 3, 4].mean # 2.5
|
@@ -92,6 +92,30 @@ samples.sorted_frequencies
|
|
92
92
|
[2, 2.0, 1].modes # [2.0]
|
93
93
|
```
|
94
94
|
|
95
|
+
## Mapping
|
96
|
+
|
97
|
+
If the thing you want stats on is buried in your objects, you can pass a block to any SimpleStats method.
|
98
|
+
|
99
|
+
```ruby
|
100
|
+
# these two lines do the same thing
|
101
|
+
cities.mean {|city| city.population}
|
102
|
+
cities.map {|city| city.population}.mean
|
103
|
+
|
104
|
+
# other examples
|
105
|
+
cities.sum(&:public_school_count)
|
106
|
+
cities.mean(&:public_school_count)
|
107
|
+
cities.frequencies(&:professional_team_count)
|
108
|
+
|
109
|
+
# more complicated examples
|
110
|
+
cities.median {|city| city.municipal_income / city.schools.sum(&:students)}
|
111
|
+
cities.map(&:schools).flatten.modes(&:team_name) # most common school sports team name
|
112
|
+
cities.map(&:professional_teams).flatten.sorted_frequencies(&:kind) # number of different kinds of sports teams
|
113
|
+
```
|
114
|
+
|
115
|
+
## Interaction with other gems
|
116
|
+
|
117
|
+
If any of SimpleStats' methods are already defined on Enumerable, SimpleStats _will not_ replace them with its own definition. In particular, ActiveSupport [defines a `sum` method](https://github.com/rails/rails/blob/master/activesupport/lib/active_support/core_ext/enumerable.rb). If both ActiveSupport and SimpleStats are used, the `sum` method will come from ActiveSupport. Don't worry, ActiveSupport and SimpleStats should work fine together.
|
118
|
+
|
95
119
|
## Help make it better!
|
96
120
|
|
97
121
|
Need something added? [Open an issue](https://github.com/brianhempel/simple_stats/issues). Or, even better, code it yourself and send a pull request:
|
@@ -106,4 +130,4 @@ Need something added? [Open an issue](https://github.com/brianhempel/simple_stat
|
|
106
130
|
|
107
131
|
## License
|
108
132
|
|
109
|
-
Public domain. (I, Brian Hempel, the original author release this code to the public domain.)
|
133
|
+
Public domain. (I, Brian Hempel, the original author release this code to the public domain. February 10, 2012.)
|
data/Rakefile
CHANGED
@@ -1 +1,10 @@
|
|
1
1
|
require "bundler/gem_tasks"
|
2
|
+
|
3
|
+
task :default => :test
|
4
|
+
|
5
|
+
desc "Run the tests (rspec)"
|
6
|
+
task(:test) do
|
7
|
+
require 'rspec/autorun'
|
8
|
+
$LOAD_PATH.unshift(File.expand_path '../spec', __FILE__)
|
9
|
+
Dir.glob(File.expand_path '../spec/**/*_spec.rb', __FILE__).each {|s| require s}
|
10
|
+
end
|
@@ -1,65 +1,91 @@
|
|
1
1
|
module Enumerable
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
count = self.count # count has to iterate if there's no size method
|
8
|
-
return nil if count == 0
|
9
|
-
sum / count.to_f
|
2
|
+
unless method_defined? :sum
|
3
|
+
def sum(&block)
|
4
|
+
return map(&block).sum if block_given?
|
5
|
+
inject(0) { |sum, x| sum + x }
|
6
|
+
end
|
10
7
|
end
|
11
8
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
i = count / 2
|
9
|
+
unless method_defined? :mean
|
10
|
+
def mean(&block)
|
11
|
+
return map(&block).mean if block_given?
|
16
12
|
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
else
|
21
|
-
( sorted[i-1] + sorted[i] ) / 2.0
|
13
|
+
count = self.count # count has to iterate if there's no size method
|
14
|
+
return nil if count == 0
|
15
|
+
(sum / count.to_f).to_f
|
22
16
|
end
|
23
17
|
end
|
24
18
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
19
|
+
unless method_defined? :median
|
20
|
+
def median(&block)
|
21
|
+
return map(&block).median if block_given?
|
22
|
+
|
23
|
+
sorted = sort
|
24
|
+
count = sorted.size
|
25
|
+
i = count / 2
|
26
|
+
|
27
|
+
return nil if count == 0
|
28
|
+
if count % 2 == 1
|
29
|
+
sorted[i]
|
30
|
+
else
|
31
|
+
( sorted[i-1] + sorted[i] ) / 2.0
|
32
|
+
end.to_f
|
31
33
|
end
|
32
34
|
end
|
33
35
|
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
36
|
+
unless method_defined? :modes
|
37
|
+
def modes(&block)
|
38
|
+
return map(&block).modes if block_given?
|
39
|
+
|
40
|
+
sorted_frequencies = self.sorted_frequencies
|
41
|
+
sorted_frequencies.select do |item, frequency|
|
42
|
+
frequency == sorted_frequencies.first[1]
|
43
|
+
end.map do |item, frequency|
|
44
|
+
item
|
40
45
|
end
|
41
46
|
end
|
42
|
-
|
47
|
+
end
|
43
48
|
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
49
|
+
unless method_defined? :frequencies
|
50
|
+
# This function is oddly written in order to group 1 (integer) and 1.0 (float) together.
|
51
|
+
# If we loaded a hash or used group_by, 1 and 1.0 would be counted as separate things.
|
52
|
+
# Instead, we use the == operator for grouping.
|
53
|
+
def frequencies(&block)
|
54
|
+
return map(&block).frequencies if block_given?
|
55
|
+
|
56
|
+
begin
|
57
|
+
sorted = sort
|
58
|
+
rescue NoMethodError # i.e. undefined method `<=>' for :my_symbol:Symbol
|
59
|
+
sorted = sort_by do |item|
|
60
|
+
item.respond_to?(:"<=>") ? item : item.to_s
|
52
61
|
end
|
53
62
|
end
|
54
|
-
|
63
|
+
current_item = nil;
|
64
|
+
|
65
|
+
Hash[
|
66
|
+
sorted.reduce([]) do |frequencies, item|
|
67
|
+
if frequencies.size == 0 || item != current_item
|
68
|
+
current_item = item
|
69
|
+
frequencies << [item, 1]
|
70
|
+
else
|
71
|
+
frequencies.last[1] += 1
|
72
|
+
frequencies
|
73
|
+
end
|
74
|
+
end
|
75
|
+
]
|
76
|
+
end
|
55
77
|
end
|
56
78
|
|
57
|
-
|
58
|
-
|
59
|
-
if
|
60
|
-
|
61
|
-
|
62
|
-
|
79
|
+
unless method_defined? :sorted_frequencies
|
80
|
+
def sorted_frequencies(&block)
|
81
|
+
return map(&block).sorted_frequencies if block_given?
|
82
|
+
|
83
|
+
frequencies.sort_by do |item, frequency|
|
84
|
+
if item.respond_to?(:"<=>")
|
85
|
+
[-frequency, item]
|
86
|
+
else
|
87
|
+
[-frequency, item.to_s]
|
88
|
+
end
|
63
89
|
end
|
64
90
|
end
|
65
91
|
end
|
data/lib/simple_stats/version.rb
CHANGED
@@ -25,5 +25,15 @@ describe Enumerable do
|
|
25
25
|
frequencies.class.should == expected.class
|
26
26
|
end
|
27
27
|
end
|
28
|
+
|
29
|
+
it "calls map first if a block is given" do
|
30
|
+
f = Struct.new(:x)
|
31
|
+
data = [f.new(:a), f.new(:b), f.new(:b)]
|
32
|
+
frequencies = data.frequencies(&:x)
|
33
|
+
frequencies.should == {
|
34
|
+
:a => 1,
|
35
|
+
:b => 2
|
36
|
+
}
|
37
|
+
end
|
28
38
|
end
|
29
|
-
end
|
39
|
+
end
|
@@ -28,5 +28,11 @@ describe Enumerable do
|
|
28
28
|
["White-breasted Nuthatch", 1]
|
29
29
|
]
|
30
30
|
end
|
31
|
+
|
32
|
+
it "calls map first if a block is given" do
|
33
|
+
f = Struct.new(:x)
|
34
|
+
data = [f.new(:a), f.new(:b), f.new(:b)]
|
35
|
+
data.sorted_frequencies(&:x).should == [[:b, 2], [:a, 1]]
|
36
|
+
end
|
31
37
|
end
|
32
38
|
end
|
data/spec/enumerable/sum_spec.rb
CHANGED
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: simple_stats
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 19
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 1
|
8
|
+
- 1
|
8
9
|
- 0
|
9
|
-
|
10
|
-
version: 1.0.0
|
10
|
+
version: 1.1.0
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Brian Hempel
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date:
|
18
|
+
date: 2013-12-16 00:00:00 Z
|
19
19
|
dependencies: []
|
20
20
|
|
21
21
|
description: Simple mean, median, modes, sum, and frequencies for Ruby arrays and enumerables. Tested and sensible.
|
@@ -74,7 +74,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
74
74
|
requirements: []
|
75
75
|
|
76
76
|
rubyforge_project:
|
77
|
-
rubygems_version: 1.8.
|
77
|
+
rubygems_version: 1.8.26
|
78
78
|
signing_key:
|
79
79
|
specification_version: 3
|
80
80
|
summary: Simple mean, median, modes, sum, and frequencies for Ruby arrays and enumerables. Tested and sensible.
|