davidrichards-just_enumerable_stats 0.0.2

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.
@@ -0,0 +1,449 @@
1
+ require File.dirname(__FILE__) + '/spec_helper'
2
+
3
+ describe "JustEnumerableStats" do
4
+
5
+ before do
6
+ @a = [1,2,3]
7
+ @b = [8,4,2]
8
+ @doubler = lambda{|e| e * 2}
9
+ @inverser = lambda{|e| 1/e.to_f}
10
+ @inverse_matcher = lambda{|a, b| 1/a <=> 1/b}
11
+ end
12
+
13
+ it "should be able to generate a random number between two integers" do
14
+ val = (1..100).map {rand_between(1,10)}
15
+ (val.min >= 1).should be_true
16
+ (val.max <= 10).should be_true
17
+ end
18
+
19
+ it "should be able to generate a random number between two floats" do
20
+ val = (1..100).map {rand_in_floats(1.0,10.0)}
21
+ (val.min >= 1).should be_true
22
+ (val.max <= 10).should be_true
23
+ val.all? {|v| v.should be_is_a(Float)}
24
+ end
25
+
26
+ it "should be able to work with floats from rand_between" do
27
+ val = (1..100).map {rand_between(1.0,10.0)}
28
+ (val.min >= 1).should be_true
29
+ (val.max <= 10).should be_true
30
+ val.all? {|v| v.should be_is_a(Float)}
31
+ end
32
+
33
+ it "should have an original max" do
34
+ @a.original_max.should eql(3)
35
+ end
36
+
37
+ it "should have an original min" do
38
+ @a.original_min.should eql(1)
39
+ end
40
+
41
+ it "should have a max" do
42
+ @a.max.should eql(3)
43
+ end
44
+
45
+ it "should have a max that takes a block" do
46
+ val = @a.max &@inverse_matcher
47
+ val.should eql(1)
48
+ end
49
+
50
+ it "should be able to use a default block for max" do
51
+ @a.default_block = @inverse_matcher
52
+ @a.max.should eql(1)
53
+ end
54
+
55
+ it "should know the index of the max value" do
56
+ @a.max_index.should eql(2)
57
+ end
58
+
59
+ it "should find the first index value with max_index, in case there are duplicates" do
60
+ [1,2,3,3].max_index.should eql(2)
61
+ end
62
+
63
+ it "should use a block to find the max index" do
64
+ val = @a.max_index &@inverse_matcher
65
+ val.should eql(0)
66
+ end
67
+
68
+ it "should be able to use a default block to find the max index" do
69
+ @a.default_block = @inverse_matcher
70
+ @a.max_index.should eql(0)
71
+ end
72
+
73
+ it "should have a min" do
74
+ @a.min.should eql(1)
75
+ end
76
+
77
+ it "should have a min that takes a block" do
78
+ val = @a.min &@inverse_matcher
79
+ val.should eql(3)
80
+ end
81
+
82
+ it "should be able to use a default block for min" do
83
+ @a.default_block = @inverse_matcher
84
+ @a.min.should eql(3)
85
+ end
86
+
87
+ it "should know the index of the min value" do
88
+ @a.min_index.should eql(0)
89
+ end
90
+
91
+ it "should find the first index value with min_index, in case there are duplicates" do
92
+ [1,1,2,3].min_index.should eql(0)
93
+ end
94
+
95
+ it "should use a block to find the min index" do
96
+ val = @a.min_index &@inverse_matcher
97
+ val.should eql(2)
98
+ end
99
+
100
+ it "should be able to use a default block to find the min index" do
101
+ @a.default_block = @inverse_matcher
102
+ @a.min_index.should eql(2)
103
+ end
104
+
105
+ it "should be able to sum a list" do
106
+ @a.sum.should eql(6)
107
+ [1, 2, 3.0].sum.should eql(6.0)
108
+ end
109
+
110
+ it "should offer sum with a precision of 1.0e-15" do
111
+ [0.1, 0.2, 0.3].sum.should be_close(0.6, 1.0e-15)
112
+ [0.1, 0.2, 0.3].sum.should_not be_close(0.6, 1.0e-16)
113
+ end
114
+
115
+ it "should be able to evaluate a sum with a block" do
116
+ @a.sum(&@doubler).should eql(12)
117
+ end
118
+
119
+ it "should be able to use the default block to evaluate sum" do
120
+ @a.default_block = @doubler
121
+ @a.sum.should eql(12)
122
+ end
123
+
124
+ it "should be able to find the arithmetic average, mean, or avg" do
125
+ @a.average.should eql(2)
126
+ @a.mean.should eql(2)
127
+ @a.avg.should eql(2)
128
+ [1, 2, 3.0].average.should eql(2.0)
129
+ end
130
+
131
+ it "should be able to calculate average with a block" do
132
+ @a.average(&@doubler).should eql(4)
133
+ @a.mean(&@doubler).should eql(4)
134
+ @a.avg(&@doubler).should eql(4)
135
+ [1, 2, 3.0].average(&@doubler).should eql(4.0)
136
+ end
137
+
138
+ it "should be able to calculate average with a default block" do
139
+ @a.default_block = @doubler
140
+ @a.average.should eql(4)
141
+ @a.mean.should eql(4)
142
+ @a.avg.should eql(4)
143
+ b = [1, 2, 3.0]
144
+ b.default_block = @doubler
145
+ b.average.should eql(4.0)
146
+ end
147
+
148
+ it "should be able to calculate the variance" do
149
+ @a.variance.should eql(1)
150
+ @a.var.should eql(1)
151
+ end
152
+
153
+ it "should be able to calculate the variance with a block" do
154
+ @a.variance(&@doubler).should eql(4)
155
+ @a.var(&@doubler).should eql(4)
156
+ end
157
+
158
+ it "should be able to calculate the variance with a default block" do
159
+ @a.default_block = @doubler
160
+ @a.variance.should eql(4)
161
+ @a.var.should eql(4)
162
+ end
163
+
164
+ it "should be able to calculate the standard deviation" do
165
+ @a.standard_deviation.should eql(1.0)
166
+ @a.std.should eql(1.0)
167
+ end
168
+
169
+ it "should be able to calculate the standard deviation with a block" do
170
+ @a.standard_deviation(&@doubler).should eql(2.0)
171
+ @a.std(&@doubler).should eql(2.0)
172
+ end
173
+
174
+ it "should be able to calculate the standard deviation with a default block" do
175
+ @a.default_block = @doubler
176
+ @a.standard_deviation.should eql(2.0)
177
+ @a.std.should eql(2.0)
178
+ end
179
+
180
+ it "should be able to calculate the median value" do
181
+ @a.median.should eql(2)
182
+ [1,4,3,2,5].median.should eql(3)
183
+ [1,9,2,8].median.should eql(5.0)
184
+ end
185
+
186
+ it "should be able to get a max and min range from the list" do
187
+ @a.range.should eql([1, 3])
188
+ end
189
+
190
+ it "should be able to pass a block to the range method" do
191
+ @a.range(&@inverse_matcher).should eql([3, 1])
192
+ end
193
+
194
+ it "should be able to use a default block for the range method" do
195
+ @a.default_block = @inverse_matcher
196
+ @a.range.should eql([3, 1])
197
+ end
198
+
199
+ it "should have a getter and a setter on the range class" do
200
+ @a.range_class = Array
201
+ @a.range_class.should eql(Array)
202
+ end
203
+
204
+ it "should be able to instantiate a range" do
205
+ @a.range_as_range.should eql(Range.new(1, 3))
206
+ end
207
+
208
+ it "should be able to instantiate a range with a block" do
209
+ @a.range_as_range(&@inverse_matcher).should eql(Range.new(3, 1))
210
+ end
211
+
212
+ it "should be able to instantiate a range with a default block" do
213
+ @a.default_block = @inverse_matcher
214
+ @a.range_as_range.should eql(Range.new(3, 1))
215
+ end
216
+
217
+ it "should be able to create a new object, sorted" do
218
+ a = [3,1,2]
219
+ b = a.new_sort
220
+ b.object_id.should_not eql(a.object_id)
221
+ b.should eql([1,2,3])
222
+ a << 4
223
+ b.should eql([1,2,3])
224
+ end
225
+
226
+ it "should be able to take a block and still do new_sort" do
227
+ @a.new_sort(&@doubler).should eql([2,4,6])
228
+ end
229
+
230
+ it "should be able to take a default block and still do new_sort" do
231
+ @a.default_block = @doubler
232
+ @a.new_sort.should eql([2,4,6])
233
+ end
234
+
235
+ it "should be able to rank a list" do
236
+ @b.rank.should eql([3,2,1])
237
+ end
238
+
239
+ it "should be able to use a block in rank" do
240
+ @b.rank(&@inverser).should eql([1,2,3])
241
+ end
242
+
243
+ it "should be able to use a default block in rank" do
244
+ @b.default_block = @inverser
245
+ @b.rank.should eql([1,2,3])
246
+ end
247
+
248
+ it "should be able to get the order of values, handling duplicates" do
249
+ [10,5,5,1].order.should eql([4,2,3,1])
250
+ end
251
+
252
+ it "should be able to take a block in the ordering" do
253
+ [10,5,5,1].order(&@inverser).should eql([1,2,3,4])
254
+ end
255
+
256
+ it "should be able to take a default block in the ordering" do
257
+ a = [10,5,5,1]
258
+ a.default_block = @inverser
259
+ a.order.should eql([1,2,3,4])
260
+ end
261
+
262
+ it "should be able to calculate the cumulative sum" do
263
+ @a.cumulative_sum.should eql([1,3,6])
264
+ @a.cum_sum.should eql([1,3,6])
265
+ [1,2,3.0].cum_sum.should eql([1.0, 3.0, 6.0])
266
+ end
267
+
268
+ it "should be able to take a block to produce the cumulative sum" do
269
+ @a.cumulative_sum(&@doubler).should eql([2,6,12])
270
+ @a.cum_sum(&@doubler).should eql([2,6,12])
271
+ [1,2,3.0].cum_sum(&@doubler).should eql([2.0, 6.0, 12.0])
272
+ end
273
+
274
+ it "should be able to take a default block to produce the cumlative sum" do
275
+ @a.default_block = @doubler
276
+ @a.cumulative_sum.should eql([2,6,12])
277
+ @a.cum_sum.should eql([2,6,12])
278
+ b = [1,2,3.0]
279
+ b.default_block = @doubler
280
+ b.cum_sum.should eql([2.0, 6.0, 12.0])
281
+ end
282
+
283
+ it "should be able to calculate the cumulative product" do
284
+ @a.cumulative_product.should eql([1,2,6])
285
+ @a.cum_prod.should eql([1,2,6])
286
+ [1,2,3.0].cum_prod.should eql([1.0, 2.0, 6.0])
287
+ end
288
+
289
+ it "should be able to take a block to produce the cumulative product" do
290
+ @a.cumulative_product(&@doubler).should eql([2,8,48])
291
+ @a.cum_prod(&@doubler).should eql([2,8,48])
292
+ [1,2,3.0].cum_prod(&@doubler).should eql([2.0, 8.0, 48.0])
293
+ end
294
+
295
+ it "should be able to take a default block to produce the cumlative product" do
296
+ @a.default_block = @doubler
297
+ @a.cumulative_product.should eql([2,8,48])
298
+ @a.cum_prod.should eql([2,8,48])
299
+ b = [1,2,3.0]
300
+ b.default_block = @doubler
301
+ b.cum_prod.should eql([2.0, 8.0, 48.0])
302
+ end
303
+
304
+ it "should be able to produce the cumulative max" do
305
+ @a.cumulative_max.should eql([1,2,3])
306
+ @a.cum_max.should eql([1,2,3])
307
+ end
308
+
309
+ it "should be able to produce the cumulative max with a block" do
310
+ @a.cumulative_max(&@doubler).should eql([2,4,6])
311
+ @a.cum_max(&@doubler).should eql([2,4,6])
312
+ end
313
+
314
+ it "should be able to produce the cumulative max with a default block" do
315
+ @a.default_block = @doubler
316
+ @a.cumulative_max.should eql([2,4,6])
317
+ @a.cum_max.should eql([2,4,6])
318
+ end
319
+
320
+ it "should be able to produce the cumulative min" do
321
+ @a.cumulative_min.should eql([1,1,1])
322
+ @a.cum_min.should eql([1,1,1])
323
+ end
324
+
325
+ it "should be able to produce the cumulative min with a block" do
326
+ @a.cumulative_min(&@doubler).should eql([2,2,2])
327
+ @a.cum_min(&@doubler).should eql([2,2,2])
328
+ end
329
+
330
+ it "should be able to produce the cumulative min with a default block" do
331
+ @a.default_block = @doubler
332
+ @a.cumulative_min.should eql([2,2,2])
333
+ @a.cum_min.should eql([2,2,2])
334
+ end
335
+
336
+ it "should be able to multiply the values in the list" do
337
+ @a.product.should eql(6)
338
+ end
339
+
340
+ it "should be able to yield an operation on pairs" do
341
+ val = @a.to_pairs(@b) {|a, b| a + b}
342
+ val.should eql([9,6,5])
343
+ end
344
+
345
+ # [1,2,3] and [2,3,4] have 2 items in common, and 4 unique items together.
346
+ # So 2 items / 4 items is 0.5
347
+ it "should be able to find the tanimoto coefficient" do
348
+ b = [2,3,4]
349
+ @a.tanimoto_pairs(b).should eql(0.5)
350
+ @a.tanimoto_correlation(b).should eql(0.5)
351
+ end
352
+
353
+ it "should have long hand for union" do
354
+ @a.union(@b).should eql([1, 2, 3, 8, 4])
355
+ end
356
+
357
+ it "should have long hand for intersect" do
358
+ @a.intersect(@b).should eql([2])
359
+ end
360
+
361
+ it "should have a long hand for compliment" do
362
+ @a.compliment(@b).should eql([1, 3])
363
+ end
364
+
365
+ it "should have a long hand for exclusive not" do
366
+ @a.exclusive_not(@b).should eql([1,3,8,4])
367
+ end
368
+
369
+ it "should be able to generate a cartesian product" do
370
+ @a.cartesian_product(@b).should eql([[1, 8], [1, 4], [1, 2], [2, 8], [2, 4], [3, 8], [3, 4], [3, 2]])
371
+ @a.cp(@b).should eql([[1, 8], [1, 4], [1, 2], [2, 8], [2, 4], [3, 8], [3, 4], [3, 2]])
372
+ @a.permutations(@b).should eql([[1, 8], [1, 4], [1, 2], [2, 8], [2, 4], [3, 8], [3, 4], [3, 2]])
373
+ end
374
+
375
+ it "should be able to add pairwise computations" do
376
+ # Remember:
377
+ # @a = [1,2,3]
378
+ # @b = [8,4,2]
379
+ val = @a.sigma_pairs(@b) {|a, b| a / b}
380
+ val.should eql(1/8 + 2/4 + 3/2)
381
+ val = @a.sigma_pairs(@b) {|a, b| a * b}
382
+ val.should eql(1*8 + 2*4 + 3*2)
383
+ end
384
+
385
+ it "should be able to find the euclidian distance between two lists" do
386
+ @a.euclidian_distance(@b).should be_close(7.348, 0.001)
387
+ [1,2,3].euclidian_distance([2,3,4]).should eql(Math.sqrt(3.0))
388
+ end
389
+
390
+ it "should be able to generate a list of random numbers, each within the range between two lists" do
391
+ a = [1,0,-1]
392
+ b = [10,0,-20]
393
+ list_min = a.min_of_lists(b)
394
+ list_max = a.max_of_lists(b)
395
+ 100.times do
396
+ val = a.rand_in_range(b)
397
+ val.each_with_index do |e, i|
398
+ e >= list_min[i]
399
+ e <= list_max[i]
400
+ end
401
+ end
402
+ end
403
+
404
+ it "should be able to find random numbers in the range between many lists" do
405
+ a = [1,0,-2]
406
+ b = [10,0,-20]
407
+ c = [2,0,-1]
408
+ list_min = a.min_of_lists(b)
409
+ list_max = a.max_of_lists(b)
410
+ 100.times do
411
+ val = a.rand_in_range(b)
412
+ val.each_with_index do |e, i|
413
+ e >= list_min[i]
414
+ e <= list_max[i]
415
+ end
416
+ end
417
+ end
418
+
419
+ it "should be able to yield a block for columns of values" do
420
+ a = [1,2,6.0]
421
+ b = [2,6.0,1]
422
+ c = [6.0,1,2]
423
+ val = a.yield_transpose(b, c) {|e| e.mean}
424
+ val.should eql([3.0, 3.0, 3.0])
425
+ end
426
+
427
+ it "should be able to transpose a list of lists (not dependent on Array#transpose)" do
428
+ a = [1,2,6.0]
429
+ b = [2,6.0,1]
430
+ c = [6.0,1,2]
431
+ val = a.yield_transpose(b, c)
432
+ val.should eql( [[1, 2, 6.0], [2, 6.0, 1], [6.0, 1, 2]])
433
+ end
434
+
435
+ it "should be able to get the correlation between two lists" do
436
+ @a.correlation([2,3,5]).should be_close(0.981, 0.001)
437
+ @a.cor([2,3,5]).should be_close(0.981, 0.001)
438
+ end
439
+
440
+ it "should be able to return the max of lists" do
441
+ @a.max_of_lists(@b).should eql([8,4,3])
442
+ @a.max_of_lists(@b, [10,10,10]).should eql([10,10,10])
443
+ end
444
+
445
+ it "should be able to return the min of lists" do
446
+ @a.min_of_lists(@b).should eql([1,2,2])
447
+ end
448
+
449
+ end
@@ -0,0 +1,8 @@
1
+ $: << File.join(File.dirname(__FILE__), "/../lib")
2
+ require 'rubygems'
3
+ require 'spec'
4
+ require 'just_enumerable_stats'
5
+
6
+ Spec::Runner.configure do |config|
7
+
8
+ end