pickup 0.0.4 → 0.0.5

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -67,6 +67,21 @@ pickup.pick
67
67
  #=> "minnow"
68
68
  ```
69
69
 
70
+ ### Random uniq pick
71
+
72
+ Also we can pick random uniq items from the list
73
+
74
+ ```ruby
75
+ pickup = Pickup.new(pond, uniq: true)
76
+ pickup.pick(3)
77
+ #=> [ "gudgeon", "herring", "minnow" ]
78
+ pickup.pick
79
+ #=> "herring"
80
+ pickup.pick
81
+ #=> "gudgeon"
82
+ pickup.pick
83
+ #=> "sturgeon"
84
+ ```
70
85
 
71
86
  ## Contributing
72
87
 
@@ -4,18 +4,16 @@ class Pickup
4
4
  attr_reader :list, :uniq
5
5
  attr_writer :pick_func
6
6
 
7
- def initialize(list, uniq=false, &block)
7
+ def initialize(list, opts={}, &block)
8
8
  @list = list
9
- @uniq = uniq
9
+ @uniq = opts[:uniq] || false
10
10
  @pick_func = block if block_given?
11
11
  end
12
12
 
13
13
  def pick(count=1, &block)
14
14
  func = block || pick_func
15
15
  mlist = MappedList.new(list, func, uniq)
16
- result = count.times.map do |i|
17
- mlist.random
18
- end
16
+ result = mlist.random(count)
19
17
  count == 1 ? result.first : result
20
18
  end
21
19
 
@@ -28,44 +26,71 @@ class Pickup
28
26
  end
29
27
 
30
28
  class MappedList
29
+ include Enumerable
31
30
  attr_reader :list, :func, :uniq, :max
32
31
 
33
32
  def initialize(list, func, uniq=false)
34
33
  @func = func
35
34
  @uniq = uniq
36
- @list = map_list(list)
35
+ @list = list
36
+ @current_state = 0
37
37
  end
38
38
 
39
- def random
40
- num = rand(max)
41
- get_random_item(num)
39
+ def each(&blk)
40
+ item_iterator = next_item
41
+ item = nil
42
+ drop = false
43
+ while true do
44
+ item ||= item_iterator.call(drop)
45
+ drop = false
46
+ if uniq
47
+ drop = true if yield item
48
+ item = nil
49
+ else
50
+ item = nil unless yield item
51
+ end
52
+ end
42
53
  end
43
54
 
44
- def get_random_item(n)
45
- item = list.detect do |k,v|
46
- val = func.call v[:value]
47
- num = func.call n
48
- (val >= num) && !(uniq && v[:picked])
55
+ def next_item
56
+ dup = list.dup
57
+ start = 0
58
+ enum = dup.to_enum
59
+ item = nil
60
+ Proc.new do |drop|
61
+ dup.delete item if drop
62
+ item = begin
63
+ enum.next
64
+ rescue StopIteration => e
65
+ enum = dup.to_enum
66
+ enum.next
67
+ end
68
+ start += item[1]
69
+ item[1] = start
70
+ item
49
71
  end
50
- item ||= list.detect{ |k,v| !v[:picked] }
51
- raise "No items left" unless item
52
- key = item[0]
53
- list[key][:picked] = true if uniq
54
- key
55
72
  end
56
-
57
- private
58
73
 
59
- def map_list(list)
60
- @max = 0
61
- mapped_list = {}
62
- list.each do |k, v|
63
- mapped_list[k] = {}
64
- mapped_list[k][:value] = @max
65
- @max += v
66
- mapped_list[k][:picked] = false if uniq
74
+ def random(count)
75
+ raise "List is shorter then count of items you want to get" if uniq && list.size < count
76
+ nums = count.times.map{ func.call(rand(max)) }.sort
77
+ get_random_items(nums)
78
+ end
79
+
80
+ def get_random_items(nums)
81
+ next_num = Proc.new{ nums.shift }
82
+ current_num = next_num.call
83
+ items = []
84
+ each do |item, counter|
85
+ break unless current_num
86
+ val = func.call(counter)
87
+ if val > current_num
88
+ items << item
89
+ current_num = next_num.call
90
+ true
91
+ end
67
92
  end
68
- mapped_list
93
+ items
69
94
  end
70
95
  end
71
96
  end
@@ -1,3 +1,3 @@
1
1
  class Pickup
2
- VERSION = "0.0.4"
2
+ VERSION = "0.0.5"
3
3
  end
@@ -14,40 +14,32 @@ describe Pickup do
14
14
  }
15
15
  @func = Proc.new{ |a| a }
16
16
  @pickup = Pickup.new(@list)
17
- @pickup2 = Pickup.new(@list, true)
17
+ @pickup2 = Pickup.new(@list, uniq: true)
18
18
  end
19
19
 
20
20
  it "should pick correct ammount of items" do
21
21
  @pickup.pick(2).size.must_equal 2
22
+ @pickup.pick(10).size.must_equal 10
22
23
  end
23
24
 
24
25
  describe Pickup::MappedList do
25
26
  before do
26
- @mapped_list = {"selmon"=>{:value=>0, :picked=>false}, "carp"=>{:value=>1, :picked=>false}, "crucian"=>{:value=>5, :picked=>false}, "herring"=>{:value=>8, :picked=>false}, "sturgeon"=>{:value=>14, :picked=>false}, "gudgeon"=>{:value=>22, :picked=>false}, "minnow"=>{:value=>32, :picked=>false}}
27
27
  @ml = Pickup::MappedList.new(@list, @func, true)
28
28
  @ml2 = Pickup::MappedList.new(@list, @func)
29
29
  end
30
30
 
31
- it "should return right mapped list" do
32
- @ml.list.must_equal(@mapped_list)
33
- end
34
-
35
31
  it "should return selmon and then carp and then crucian for uniq pickup" do
36
- @ml.get_random_item(0).must_equal "selmon"
37
- @ml.get_random_item(0).must_equal "carp"
38
- @ml.get_random_item(0).must_equal "crucian"
32
+ @ml.get_random_items([0, 0, 0]).must_equal ["selmon", "carp", "crucian"]
39
33
  end
40
34
 
41
35
  it "should return selmon 3 times for non-uniq pickup" do
42
- @ml2.get_random_item(0).must_equal "selmon"
43
- @ml2.get_random_item(0).must_equal "selmon"
44
- @ml2.get_random_item(0).must_equal "selmon"
36
+ @ml2.get_random_items([0]).first.must_equal "selmon"
37
+ @ml2.get_random_items([0]).first.must_equal "selmon"
38
+ @ml2.get_random_items([0]).first.must_equal "selmon"
45
39
  end
46
40
 
47
41
  it "should return item from the beginning after end of list for uniq pickup" do
48
- @ml.get_random_item(20).must_equal "gudgeon"
49
- @ml.get_random_item(20).must_equal "minnow"
50
- @ml.get_random_item(20).must_equal "selmon"
42
+ @ml.get_random_items([20, 20, 20, 20]).must_equal ["sturgeon", "gudgeon", "minnow", "selmon"]
51
43
  end
52
44
  end
53
45
 
@@ -55,4 +47,8 @@ describe Pickup do
55
47
  items = @pickup2.pick(7)
56
48
  items.uniq.size.must_equal 7
57
49
  end
50
+
51
+ it "should raise an exception" do
52
+ proc{ items = @pickup2.pick(8) }.must_raise RuntimeError
53
+ end
58
54
  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
4
+ version: 0.0.5
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: 2012-05-31 00:00:00.000000000 Z
12
+ date: 2012-06-01 00:00:00.000000000 Z
13
13
  dependencies: []
14
14
  description: Pickup helps you to pick item from collection by it's weight/probability
15
15
  email:
@@ -48,7 +48,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
48
48
  version: '0'
49
49
  requirements: []
50
50
  rubyforge_project:
51
- rubygems_version: 1.8.23
51
+ rubygems_version: 1.8.24
52
52
  signing_key:
53
53
  specification_version: 3
54
54
  summary: Pickup helps you to pick item from collection by it's weight/probability