aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to '_plugins/lib/weightedrandomizer.rb')
-rw-r--r--_plugins/lib/weightedrandomizer.rb60
1 files changed, 60 insertions, 0 deletions
diff --git a/_plugins/lib/weightedrandomizer.rb b/_plugins/lib/weightedrandomizer.rb
new file mode 100644
index 0000000..6d36b92
--- /dev/null
+++ b/_plugins/lib/weightedrandomizer.rb
@@ -0,0 +1,60 @@
+# Implements weighted randomization for a group of weighted items.
+# This class expects a hash of key -> value pairs where the value is
+# the weight for the item.
+#
+# @example Usage
+# wr = WeightedRandomizer.new('queue1' => 25, 'queue2' => 100, 'queue3' => 2)
+# puts "Using queue #{wr.sample}"
+#
+# @note Mostly adapted from recipe 5.11 from the Ruby Cookbook.
+class WeightedRandomizer
+ VERSION = '0.1.2'
+
+ # Creates a new instance.
+ #
+ # @param [Hash] items the weighted items (key item, value weight)
+ # @return [WeightedRandomizer]
+ def initialize(items)
+ @items = normalize(items)
+ end
+
+ # Returns one or more weighted random values.
+ #
+ # @param [Integer] num the number of samples to return
+ # @return [Object, Array<Object>] one or more sampled items
+ def sample(num = nil)
+ return _sample unless num
+ Array.new(num) { _sample }
+ end
+
+ private
+
+ # Returns a single weighted random value.
+ #
+ # @return [Object] the weighted item
+ def _sample
+ pick = rand
+ @items.each do |key, weight|
+ return key if pick <= weight
+ pick -= weight
+ end
+ nil
+ end
+
+ # Normalizes the weights to float values so that
+ # arbitrary integer/float weights can be specified.
+ #
+ # @param [Hash] items the weighted items (key item, value weight)
+ # @return [Hash] the items with their weights normalized
+ def normalize(items)
+ normalized = {}
+ sum = items.values.inject(0.0, :+)
+ items.each do |key, weight|
+ normalized[key] = weight / sum
+ end
+
+ normalized
+ end
+end
+
+