3

For example I have this data:

headings = { 
         :heading1 => { :weight => 60, :show_count => 0}
         :heading2 => { :weight => 10, :show_count => 0}
         :heading3 => { :weight => 20, :show_count => 0}
         :heading4 => { :weight => 10, :show_count => 0}
       }
total_views = 0

Now I want to serve each heading based on their weightages. For instance, for first 10 requests/iterations, heading1, heading3, heading2 and heading4 would be served 6, 2, 1, and 1 times respectively in order (by weight).

For every iteration show_count of served heading will increment by one and total_views will also increment globally.

Could you please suggest an algorithm or some ruby code to handle this.

Bhargav Rao
  • 50,140
  • 28
  • 121
  • 140
Saim
  • 2,471
  • 5
  • 30
  • 43
  • 2
    If you're not getting an answer, it's probably because nobody has a good one. This would be an excellent opportunity to do some exploratory research and make your own solution! You can also try posting a bounty to garner more interest, but please refrain from simply posting a [duplicate question](http://stackoverflow.com/questions/5031163/server-page-based-on-weightage/5041058). – wersimmon Mar 01 '11 at 14:14
  • echoback, thanks for you comments. The reason for duplicate answer is that I haven't get any reply on it and I tried to simplify the problem statement to get some answer. Kind of A/B testing :). How to post a bounty? – Saim Mar 01 '11 at 14:19
  • 1
    There are some details in the [StackOverflow FAQ](http://stackoverflow.com/faq#bounty) about what to do if you're not getting answers. To post a bounty, click the "start a bounty" link underneath the "add comment" link on any question you've asked. – wersimmon Mar 01 '11 at 18:08

2 Answers2

6

You can use pickup gem

It accepts hash like this:

require 'pickup'
headings = {
  heading1: 60,
  heading2: 10,
  heading3: 20,
  heading4: 10
}
pickup = Pickup.new(headings)
pickup.pick
#=> heading1
pickup.pick
#=> heading1
pickup.pick
#=> heading3
pickup.pick
#=> heading1
pickup.pick
#=> heading4

So you can do something like this:

require 'pickup'

headings = { 
  heading1: { :weight => 60, :show_count => 0},
  heading2: { :weight => 10, :show_count => 0},
  heading3: { :weight => 20, :show_count => 0},
  heading4: { :weight => 10, :show_count => 0}
}

pickup_headings = headings.inject({}){ |h, (k,v)| h[k] = v[:weight]; h}

pickup = Pickup.new(pickup_headings)

# let's fire it 1000 times
1000.times do
  server = pickup.pick
  headings[server][:show_count] += 1
end

puts headings
#=> {
#=>   :heading1=>{:weight=>60, :show_count=>601},
#=>   :heading2=>{:weight=>10, :show_count=>116},
#=>   :heading3=>{:weight=>20, :show_count=>176},
#=>   :heading4=>{:weight=>10, :show_count=>107}
#=> }
fl00r
  • 82,987
  • 33
  • 217
  • 237
2

This should work for your basic case and can be modified according to the details of what you need:

 class Heading
   attr_reader :heading, :weight, :show_count

   def initialize(heading,weight=1)
     @heading=heading
     @weight=weight
     @show_count=0
   end

   def serve
     puts "Served #{@heading}! "  
     @show_count += 1
   end
 end

 class HeadingServer
   attr_reader :headings

   def initialize(headings_hash)
     @headings=headings_hash.map {|h, data| Heading.new(h,data[:weight])}
     @total_weight=@headings.inject(0) {|s,h| s+= h.weight}
   end

   def serve(num_to_serve=@total_weight)
     @headings.sort {|a,b| b.weight <=> a.weight}.each do |h| 
       n = (h.weight * num_to_serve) / @total_weight  #possibility of rounding errors
       n.times { h.serve }
     end
   end

   def total_views
     @headings.inject(0) {|s,h| s += h.show_count}
   end
 end

headings = { 
  :heading1 => { :weight => 60, :show_count => 0},
  :heading2 => { :weight => 10, :show_count => 0},
  :heading3 => { :weight => 20, :show_count => 0},
  :heading4 => { :weight => 10, :show_count => 0}
}

# Example Usage:

hs = HeadingServer.new(headings)

hs.serve(10)  

hs.headings.each {|h| puts "#{h.heading} : served #{h.show_count} times"}

puts "Total Views: #{hs.total_views}" 
Chris Turner
  • 109
  • 3
  • Chris, thanks a lot for your effort. I really appreciate that. Although, it's working fine. But we need to tweak it a bit to make it work in our application. Let me tell you how it actually work. There will be a single serve request at a time. We'll have the show_count for every heading saved in the database and it will be incremented every time a heading is served. We also will have the total_view saved in the database. Now when a serve request comes in we need to find which heading should be served based on its weight, show_count and total_views. Would you be kind enough to look into it too. – Saim Mar 02 '11 at 11:19