Weighted randomization extension for ActiveRecord.
Gives ability to get weighted random record from particular database relation.
gem 'weighted_random'
Generate model with weight
and cumulative_weight
integer attributes:
rails g model your_model [your_attributes] weight:integer cumulative_weight:integer
Or add these two attributes into migration of existing model:
create_table :your_table, do |t| t.integer :weight t.integer :cumulative_weight end
It is a good idea to add index on cumulative_weight
attribute:
add_index :your_table, :cumulative_weight
Based on Benchmark.bmbm
times, it makes creating of records 2 times faster and getting a random record 11 times faster!
Finally, load weighted randomization stuff into desired model and set accessibillity of weight
attribute:
class YourModel < ActiveRecord::Base weighted_randomizable attr_accessible :weight end
Just create records, each must contain weight
value:
LastName.create [ {:name => 'Smith', :weight => 10}, {:name => 'Johnson', :weight => 8}, {:name => 'Williams', :weight => 7}, {:name => 'Jones', :weight => 6}, {:name => 'Brown', :weight => 6}, {:name => 'Davis', :weight => 5}, {:name => 'Miller', :weight => 4}, {:name => 'Wilson', :weight => 3} ]
It automatically sets cumulative_weight
attribute for each record.
Here is an example of importing data from CSV file:
db/seeds/last_names.csv:
name,weight Smith,10 Johnson,8 Williams,7 Jones,6 Brown,6 Davis,5 Miller,4 Wilson,3
db/seeds.rb:
LastName.create( CSV.table(File.expand_path('seeds/last_names.csv', File.dirname(__FILE__))).collect(&:to_hash) )
To get weighed random record simply run:
LastName.weighted_rand
Demonstration:
10.times { puts LastName.weighted_rand.name } Johnson Brown Johnson Smith Smith Jones Smith Williams Miller Jones
Szymon Przybył (github.com/apocalyptiq)