pickup 0.0.4 → 0.0.5

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 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