X-Git-Url: https://projects.mako.cc/source/selectricity-live/blobdiff_plain/9abed97635edbac7fb1a687298fff5c5434cdff4..c5fda1e5174238779afd496014379d6446d1e3c1:/randarray.rb diff --git a/randarray.rb b/randarray.rb new file mode 100644 index 0000000..17961d1 --- /dev/null +++ b/randarray.rb @@ -0,0 +1,70 @@ +class Array + # Chooses a random array element from the receiver based on the weights + # provided. If _weights_ is nil, then each element is weighed equally. + # + # [1,2,3].random #=> 2 + # [1,2,3].random #=> 1 + # [1,2,3].random #=> 3 + # + # If _weights_ is an array, then each element of the receiver gets its + # weight from the corresponding element of _weights_. Notice that it + # favors the element with the highest weight. + # + # [1,2,3].random([1,4,1]) #=> 2 + # [1,2,3].random([1,4,1]) #=> 1 + # [1,2,3].random([1,4,1]) #=> 2 + # [1,2,3].random([1,4,1]) #=> 2 + # [1,2,3].random([1,4,1]) #=> 3 + # + # If _weights_ is a symbol, the weight array is constructed by calling + # the appropriate method on each array element in turn. Notice that + # it favors the longer word when using :length. + # + # ['dog', 'cat', 'hippopotamus'].random(:length) #=> "hippopotamus" + # ['dog', 'cat', 'hippopotamus'].random(:length) #=> "dog" + # ['dog', 'cat', 'hippopotamus'].random(:length) #=> "hippopotamus" + # ['dog', 'cat', 'hippopotamus'].random(:length) #=> "hippopotamus" + # ['dog', 'cat', 'hippopotamus'].random(:length) #=> "cat" + def random(weights=nil) + return random(map {|n| n.send(weights)}) if weights.is_a? Symbol + + weights ||= Array.new(length, 1.0) + total = weights.inject(0.0) {|t,w| t+w} + point = rand * total + + zip(weights).each do |n,w| + return n if w >= point + point -= w + end + end + + # Generates a permutation of the receiver based on _weights_ as in + # Array#random. Notice that it favors the element with the highest + # weight. + # + # [1,2,3].randomize #=> [2,1,3] + # [1,2,3].randomize #=> [1,3,2] + # [1,2,3].randomize([1,4,1]) #=> [2,1,3] + # [1,2,3].randomize([1,4,1]) #=> [2,3,1] + # [1,2,3].randomize([1,4,1]) #=> [1,2,3] + # [1,2,3].randomize([1,4,1]) #=> [2,3,1] + # [1,2,3].randomize([1,4,1]) #=> [3,2,1] + # [1,2,3].randomize([1,4,1]) #=> [2,1,3] + def randomize(weights=nil) + return randomize(map {|n| n.send(weights)}) if weights.is_a? Symbol + + weights = weights.nil? ? Array.new(length, 1.0) : weights.dup + + # pick out elements until there are none left + list, result = self.dup, [] + until list.empty? + # pick an element + result << list.random(weights) + # remove the element from the temporary list and its weight + weights.delete_at(list.index(result.last)) + list.delete result.last + end + + result + end +end