pickup 0.0.7 → 0.0.8
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/README.md +10 -0
- data/benchmarks/pickup.rb +72 -0
- data/lib/pickup.rb +13 -14
- data/lib/pickup/version.rb +1 -1
- data/spec/pickup/pickup_spec.rb +6 -1
- metadata +2 -1
data/README.md
CHANGED
@@ -92,6 +92,16 @@ pickup.pick(10){ |v| v**10 }
|
|
92
92
|
#=> ["minnow", "minnow", "minnow", "minnow", "minnow", "minnow", "minnow", "minnow", "minnow", "minnow"]
|
93
93
|
```
|
94
94
|
|
95
|
+
Or you can use reverse probability:
|
96
|
+
|
97
|
+
```ruby
|
98
|
+
pickup = Pickup.new(pond)
|
99
|
+
pickup.pick(10){ |v| v**(-10) }
|
100
|
+
#=> ["selmon", "selmon", "selmon", "selmon", "crucian", "selmon", "selmon", "selmon", "selmon", "selmon"]
|
101
|
+
```
|
102
|
+
|
103
|
+
Reverse
|
104
|
+
|
95
105
|
## Contributing
|
96
106
|
|
97
107
|
1. Fork it
|
@@ -0,0 +1,72 @@
|
|
1
|
+
require 'benchmark'
|
2
|
+
require './lib/pickup'
|
3
|
+
|
4
|
+
def simple_hash
|
5
|
+
@simple ||= begin
|
6
|
+
hash = {}
|
7
|
+
(1..30).to_a.each do |i|
|
8
|
+
hash["item_#{i}"] = rand(30)
|
9
|
+
end
|
10
|
+
hash
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def big_hash
|
15
|
+
@big ||= begin
|
16
|
+
hash = {}
|
17
|
+
(1..5000).to_a.each do |i|
|
18
|
+
hash["item_#{i}"] = rand(1000)
|
19
|
+
end
|
20
|
+
hash
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def big_weights_hash
|
25
|
+
@big_weights ||= begin
|
26
|
+
hash = {}
|
27
|
+
(1..5000).to_a.each do |i|
|
28
|
+
hash["item_#{i}"] = rand(100_000) + 10_000
|
29
|
+
end
|
30
|
+
hash
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def simple(uniq=false)
|
35
|
+
pickup = Pickup.new(simple_hash, uniq: uniq)
|
36
|
+
pickup.pick(10)
|
37
|
+
end
|
38
|
+
|
39
|
+
def big(uniq=false)
|
40
|
+
pickup = Pickup.new(big_hash, uniq: uniq)
|
41
|
+
pickup.pick(100)
|
42
|
+
end
|
43
|
+
|
44
|
+
def big_weights(uniq=false)
|
45
|
+
pickup = Pickup.new(big_weights_hash, uniq: uniq)
|
46
|
+
pickup.pick(100)
|
47
|
+
end
|
48
|
+
|
49
|
+
|
50
|
+
|
51
|
+
n = 500
|
52
|
+
|
53
|
+
Benchmark.bm do |x|
|
54
|
+
x.report("simple: ") do
|
55
|
+
n.times{ simple }
|
56
|
+
end
|
57
|
+
x.report("simple uniq: ") do
|
58
|
+
n.times{ simple(true) }
|
59
|
+
end
|
60
|
+
x.report("big: ") do
|
61
|
+
n.times{ big }
|
62
|
+
end
|
63
|
+
x.report("big uniq: ") do
|
64
|
+
n.times{ big(true) }
|
65
|
+
end
|
66
|
+
x.report("big weights: ") do
|
67
|
+
n.times{ big_weights }
|
68
|
+
end
|
69
|
+
x.report("big weights uniq: ") do
|
70
|
+
n.times{ big_weights(true) }
|
71
|
+
end
|
72
|
+
end
|
data/lib/pickup.rb
CHANGED
@@ -26,31 +26,27 @@ class Pickup
|
|
26
26
|
end
|
27
27
|
|
28
28
|
class CircleIterator
|
29
|
-
attr_reader :func, :obj
|
29
|
+
attr_reader :func, :obj, :max
|
30
30
|
|
31
|
-
def initialize(obj, func)
|
31
|
+
def initialize(obj, func, max)
|
32
32
|
@obj = obj.dup
|
33
33
|
@func = func
|
34
|
+
@max = max
|
34
35
|
end
|
35
36
|
|
36
37
|
def each
|
37
|
-
mx = max
|
38
38
|
until obj.empty?
|
39
39
|
start = 0
|
40
40
|
obj.each do |item, weight|
|
41
41
|
val = func.call(weight)
|
42
42
|
start += val
|
43
|
-
if yield([item, start,
|
43
|
+
if yield([item, start, max])
|
44
44
|
obj.delete item
|
45
|
-
|
45
|
+
@max -= val
|
46
46
|
end
|
47
47
|
end
|
48
48
|
end
|
49
49
|
end
|
50
|
-
|
51
|
-
def max
|
52
|
-
obj.inject(0){ |mx, item| mx += func.call(item[1]) }
|
53
|
-
end
|
54
50
|
end
|
55
51
|
|
56
52
|
class MappedList
|
@@ -64,7 +60,7 @@ class Pickup
|
|
64
60
|
end
|
65
61
|
|
66
62
|
def each(&blk)
|
67
|
-
CircleIterator.new(@list, func).each do |item|
|
63
|
+
CircleIterator.new(@list, func, max).each do |item|
|
68
64
|
if uniq
|
69
65
|
true if yield item
|
70
66
|
else
|
@@ -80,14 +76,13 @@ class Pickup
|
|
80
76
|
end
|
81
77
|
|
82
78
|
def get_random_items(nums)
|
83
|
-
|
84
|
-
current_num = next_num.call
|
79
|
+
current_num = nums.shift
|
85
80
|
items = []
|
86
81
|
each do |item, counter, mx|
|
87
82
|
break unless current_num
|
88
83
|
if counter%(mx+1) > current_num%mx
|
89
84
|
items << item
|
90
|
-
current_num =
|
85
|
+
current_num = nums.shift
|
91
86
|
true
|
92
87
|
end
|
93
88
|
end
|
@@ -95,7 +90,11 @@ class Pickup
|
|
95
90
|
end
|
96
91
|
|
97
92
|
def max
|
98
|
-
|
93
|
+
@max ||= begin
|
94
|
+
max = 0
|
95
|
+
list.each{ |item| max += func.call(item[1]) }
|
96
|
+
max
|
97
|
+
end
|
99
98
|
end
|
100
99
|
end
|
101
100
|
end
|
data/lib/pickup/version.rb
CHANGED
data/spec/pickup/pickup_spec.rb
CHANGED
@@ -60,8 +60,13 @@ describe Pickup do
|
|
60
60
|
proc{ items = @pickup2.pick(8) }.must_raise RuntimeError
|
61
61
|
end
|
62
62
|
|
63
|
-
it "should return include most
|
63
|
+
it "should return include most weigtfull item (but not always - sometimes it will fail)" do
|
64
64
|
items = @pickup2.pick(2){ |v| v**20 }
|
65
65
|
(items.include? "minnow").must_equal true
|
66
66
|
end
|
67
|
+
|
68
|
+
it "should return include less weigtfull item (but not always - sometimes it will fail)" do
|
69
|
+
items = @pickup2.pick(2){ |v| v**(-20) }
|
70
|
+
(items.include? "selmon").must_equal true
|
71
|
+
end
|
67
72
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: pickup
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.8
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -23,6 +23,7 @@ files:
|
|
23
23
|
- LICENSE
|
24
24
|
- README.md
|
25
25
|
- Rakefile
|
26
|
+
- benchmarks/pickup.rb
|
26
27
|
- lib/pickup.rb
|
27
28
|
- lib/pickup/version.rb
|
28
29
|
- pickup.gemspec
|