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.
@@ -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-18mode
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
@@ -3,4 +3,6 @@ source "http://rubygems.org"
3
3
  # Specify your gem's dependencies in simple_stats.gemspec
4
4
  gemspec
5
5
 
6
- gem 'rspec'
6
+ gem 'rubysl', :platform => :rbx
7
+ gem 'rake'
8
+ gem 'rspec'
data/README.md CHANGED
@@ -77,7 +77,7 @@ samples.sorted_frequencies
77
77
  [].frequencies # {}
78
78
  [].sorted_frequencies # []
79
79
 
80
- # if elements are preset, mean and median always return floats
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
- def sum
3
- inject(0) { |sum, x| sum + x }
4
- end
5
-
6
- def mean
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
- def median
13
- sorted = sort
14
- count = sorted.size
15
- i = count / 2
9
+ unless method_defined? :mean
10
+ def mean(&block)
11
+ return map(&block).mean if block_given?
16
12
 
17
- return nil if count == 0
18
- if count % 2 == 1
19
- sorted[i].to_f
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
- def modes
26
- sorted_frequencies = self.sorted_frequencies
27
- sorted_frequencies.select do |item, frequency|
28
- frequency == sorted_frequencies.first[1]
29
- end.map do |item, frequency|
30
- item
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
- def frequencies
35
- begin
36
- sorted = sort
37
- rescue NoMethodError # i.e. undefined method `<=>' for :my_symbol:Symbol
38
- sorted = sort_by do |item|
39
- item.respond_to?(:"<=>") ? item : item.to_s
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
- current_item = nil;
47
+ end
43
48
 
44
- Hash[
45
- sorted.reduce([]) do |frequencies, item|
46
- if frequencies.size == 0 || item != current_item
47
- current_item = item
48
- frequencies << [item, 1]
49
- else
50
- frequencies.last[1] += 1
51
- frequencies
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
- def sorted_frequencies
58
- frequencies.sort_by do |item, frequency|
59
- if item.respond_to?(:"<=>")
60
- [-frequency, item]
61
- else
62
- [-frequency, item.to_s]
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
@@ -1,3 +1,3 @@
1
1
  module SimpleStats
2
- VERSION = "1.0.0"
2
+ VERSION = "1.1.0"
3
3
  end
@@ -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
@@ -24,5 +24,11 @@ describe Enumerable do
24
24
  mean.class.should == expected.class
25
25
  end
26
26
  end
27
+
28
+ it "calls map first if a block is given" do
29
+ f = Struct.new(:x)
30
+ data = [f.new(4), f.new(1), f.new(6)]
31
+ data.mean(&:x).should == 11 / 3.0
32
+ end
27
33
  end
28
34
  end
@@ -24,5 +24,11 @@ describe Enumerable do
24
24
  median.class.should == expected.class
25
25
  end
26
26
  end
27
+
28
+ it "calls map first if a block is given" do
29
+ f = Struct.new(:x)
30
+ data = [f.new(4), f.new(1), f.new(6)]
31
+ data.median(&:x).should == 4.0
32
+ end
27
33
  end
28
34
  end
@@ -25,5 +25,11 @@ describe Enumerable do
25
25
  modes.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
+ data.modes(&:x).should == [:b]
33
+ end
28
34
  end
29
35
  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
@@ -23,5 +23,11 @@ describe Enumerable do
23
23
  sum.class.should == expected.class
24
24
  end
25
25
  end
26
+
27
+ it "calls map first if a block is given" do
28
+ f = Struct.new(:x)
29
+ data = [f.new(4), f.new(1), f.new(6)]
30
+ data.sum(&:x).should == 11
31
+ end
26
32
  end
27
33
  end
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: 23
4
+ hash: 19
5
5
  prerelease:
6
6
  segments:
7
7
  - 1
8
+ - 1
8
9
  - 0
9
- - 0
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: 2012-02-10 00:00:00 Z
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.15
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.