weighted_list 0.3.0 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 925e9f3a1fba2c35de1dd9825b28702353798b5a4cbdf63e603fab141926577d
4
- data.tar.gz: cc4b917a7322de3eeddc18f00910d432d731bc24957a52bce4041a6f17ee996a
3
+ metadata.gz: deccd69f64bb1d8425b9f5c4ccecf01e9e567cd21cbbde7a0152001cfe33ab39
4
+ data.tar.gz: 326bb826fcd77d551084ddf77addf7b78710d3e82236684ddb5cb1a29d40eb09
5
5
  SHA512:
6
- metadata.gz: cefce48130c7db1b3d7a8f2c1b167f5e49ffbad70a7133142f1e70a41ec70326536ad71b1efc4d27f7716330af33af704e57e427f073fb2f268e1faa8ab7bab0
7
- data.tar.gz: 3ae2f07dbdf47e3a41d5f31453b242ec0a5bc0cb4596f240aa7ed27e74a81296a236af31337299fb9f48fa8c87c910339b12052f1f201827cc3c9e83bc910831
6
+ metadata.gz: 93138c4eca3022ec6eea9f299a23b7eaa55d4f79fad3d989e03907db748709703fe7a12dba7ccde3785c25756b39e482d50d1704b77b615277980d30f6581476
7
+ data.tar.gz: 3d915f260d8cdff3cc23d703f6bfea37e5289316f9e113b663baffbbc6b7fa67d8c4df341075e308a21f3699fc0f9e5c6bef8da25675ac25f52fa1faaf934e68
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- weighted_list (0.3.0)
4
+ weighted_list (0.4.0)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
data/README.md CHANGED
@@ -26,22 +26,30 @@ Or install it yourself as:
26
26
 
27
27
  ## Usage
28
28
  ```ruby
29
- hash = { eastern: 150, central: 92, mountain: 21, pacific: 53 }
30
- list = WeightedList[hash]
29
+ collection = { eastern: 150, central: 92, mountain: 21, pacific: 53 }
30
+ # This works too:
31
+ # collection = [[:eastern, 150], [:central, 92], [:mountain, 21], [:pacific, 53]]
32
+ list = WeightedList[collection]
31
33
 
34
+ # If you are familiar with Array#sample, none of this will surprise you:
32
35
  list.sample # => :pacific
33
36
  list.sample(1) # => [:central]
34
37
  list.sample(3) # => [:central, :eastern, :pacific]
35
38
  list.sample(100) # => [:central, :eastern, :pacific, :mountain]
36
39
 
40
+ # It acts like a proper Ruby collection should:
37
41
  list.map(&:to_s).map(&:capitalize).sort.join(', ') # => "Central, Eastern, Mountain, Pacific"
38
42
 
43
+ # For when you'd like to provide your own entropy or cleanly test deterministically.
39
44
  class CustomRandomizer
40
45
  def rand(n)
41
46
  1.0
42
47
  end
43
48
  end
44
49
  list.sample(2, random: CustomRandomizer.new) # => [:eastern, :central]
50
+
51
+ # If you want to allow repeats:
52
+ list.sample(4, with_replacement: true) # => [:eastern, :mountain, :eastern, :eastern]
45
53
  ```
46
54
 
47
55
  ## Development
@@ -12,21 +12,20 @@ class WeightedList
12
12
  end
13
13
 
14
14
  def initialize(collection)
15
- @hash = Normalizer.call(collection)
15
+ @hash = Normalizer.call(collection.clone)
16
16
  end
17
17
 
18
18
  def each(&block)
19
19
  hash.keys.each(&block)
20
20
  end
21
21
 
22
- def sample(quantity = nil, random: Random)
23
- @random = random
24
- return single_item unless quantity
25
- (0...quantity).each_with_object(initial_memo) do |_index, memo|
26
- result = Sampler.new(memo[:current_list], random: random).call
27
- memo[:chosen].push(result.chosen)
28
- memo[:current_list] = result.remaining
29
- end[:chosen].compact
22
+ def sample(quantity = nil, random: Random, with_replacement: false)
23
+ return select_item(hash, random: random).selected unless quantity
24
+ quantity.times.each_with_object(initial_memo) do |_index, memo|
25
+ result = select_item(memo[:current_list], random: random)
26
+ memo[:selected].push(result.selected)
27
+ memo[:current_list] = (with_replacement ? hash : result.remaining)
28
+ end[:selected].compact
30
29
  end
31
30
 
32
31
  private
@@ -34,10 +33,10 @@ class WeightedList
34
33
  attr_reader :hash, :random
35
34
 
36
35
  def initial_memo
37
- { chosen: [], current_list: hash }
36
+ { selected: [], current_list: hash }
38
37
  end
39
38
 
40
- def single_item
41
- Sampler.new(hash, random: random).call.chosen
39
+ def select_item(list, random:)
40
+ Sampler.new(hash: list, random: random).call
42
41
  end
43
42
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class WeightedList
2
4
  class Normalizer
3
5
  def self.call(collection)
@@ -2,22 +2,22 @@
2
2
 
3
3
  class WeightedList
4
4
  class Sampler
5
- def initialize(hash, random: Random)
6
- @hash = hash.clone
5
+ def initialize(hash:, random:)
6
+ @hash = hash
7
7
  @random = random
8
8
  end
9
9
 
10
10
  def call
11
- Result.new(chosen, remaining)
11
+ Result.new(selected, remaining)
12
12
  end
13
13
 
14
14
  private
15
15
 
16
16
  attr_reader :hash, :random
17
17
 
18
- Result = Struct.new(:chosen, :remaining)
18
+ Result = Struct.new(:selected, :remaining)
19
19
 
20
- def choose
20
+ def select
21
21
  return if hash.empty?
22
22
  current_target = random.rand(total_weight)
23
23
 
@@ -27,12 +27,12 @@ class WeightedList
27
27
  end
28
28
  end
29
29
 
30
- def chosen
31
- @chosen ||= choose
30
+ def selected
31
+ @selected ||= select
32
32
  end
33
33
 
34
34
  def remaining
35
- hash.reject { |item, _weight| chosen == item }
35
+ hash.reject { |item, _weight| selected == item }
36
36
  end
37
37
 
38
38
  def total_weight
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class WeightedList
4
- VERSION = '0.3.0'
4
+ VERSION = '0.4.0'
5
5
  end
@@ -12,7 +12,7 @@ Gem::Specification.new do |spec|
12
12
  spec.email = ['jayson.virissimo@asu.edu']
13
13
 
14
14
  spec.summary = 'Sample from a weighted list.'
15
- spec.description = 'Sample from an (enumerable) weighted list without replacement.'
15
+ spec.description = 'Randomly sample from an (enumerable) weighted list without replacement.'
16
16
  spec.homepage = 'https://github.com/jaysonvirissimo/weighted_list'
17
17
  spec.license = 'MIT'
18
18
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: weighted_list
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jayson Virissimo
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2018-10-26 00:00:00.000000000 Z
11
+ date: 2018-10-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -52,7 +52,7 @@ dependencies:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
54
  version: '3.0'
55
- description: Sample from an (enumerable) weighted list without replacement.
55
+ description: Randomly sample from an (enumerable) weighted list without replacement.
56
56
  email:
57
57
  - jayson.virissimo@asu.edu
58
58
  executables: []