SitePoint Sponsor

User Tag List

Results 1 to 2 of 2

Hybrid View

  1. #1
    SitePoint Member
    Join Date
    Jun 2009
    Posts
    1
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    Weighting a list

    Hello, I'm new here, and new to Ruby and Rails. I've worked with Ruby some in the past, so I have a bit of prior knowledge, but Rails is all new to me. I just bought Simply Rails 2. My friends and I were trying to think of an application I could build. So we thought of a application that would pick where we eat every day. (Kind of a joke, but we'll use it.) So we started planning it out and how it would work and such. So our database will need 3 columns: Name, weight, and special. Let me explain these:

    Name - Name of the restaurant

    Weight - How much we like that restaurant, and thus we want the program to be more likely to pick restaurants weighted higher

    Special - This is for if a restaurant has a special, or a deal on a certain day. This took me a bit of thinking, but here is how I decided to use this: Because it is possible for a restaurant to have more than one special per week, I needed something more than just mon, tue, wed, ect. So I've assigned each day a number:

    Mon - 1

    Tue - 2

    Wed - 4

    Thurs - 8

    Fri - 16

    Here is how this will work: If a restaurant has a special on Monday, the column will get a 1. If it has a special on Tues, it will get a 2. If it has a special on Mon and Tues, it will get a 3 (it will get a 3 because that is Monday and Tuesday added -> 1 + 2 = 3).

    So the app needs to look at the day, and look at the special column, and see if the number means that it has a special today. If it does, then it needs to multiply the weight by 10.

    Now the part that I can't figure out, is how to weight the restaurants. My friend suggested that I use an array, and have the restaurant put in the array the number of times that it is weighted (So if it had a weight of 5, it would be put in the array 5 times). This would work, but I figured that there must be a better way. This way just seems kinda hacky. But maybe I'm wrong and it is the exact way a expert programmer would do it.

    All that being said, here's what I've done so far:

    Set up the database using SQLite, by creating a model, and then migrating it. Then I created a Restaurant controller which will have an index method that will basically do everything I've said above. It will have a new method that will let us add restaurants to the list. And here we need some check boxes for the days of the weeks, which the program can use to figure out the special number.

    If you've read all of this, I greatly thank you, and I look forward to hearing your suggestions.

  2. #2
    SitePoint Member
    Join Date
    Jun 2009
    Posts
    1
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Your friend's solution with adding multiple copies into a list is not a bad one but you're also right in that it can be done a little more elequently.

    Here's a method that will generate a random selection with a weighting per element. It basically sums all the weights, picks a random number from 1 to that sum and then scans through the elements until it finds one that matches the random 'point'

    Code Ruby:
    def get_weighted_random(hash)
      total = hash.inject(0) {|total, item_and_weight| 
                total += item_and_weight[1]}
      target = rand(total)
      hash.each do |item, weight|
        return item if target <= weight
        target -= weight
      end
    end

    You can then setup your weighted hash like:
    Code Ruby:
    weighted = {
      :one => 3,
      :two => 6,
      :three => 9
    }

    And call it:
    Code Ruby:
    result = get_weighted_random(weighted)

    It isn't very effective with small weights like, 1, 2 & 3 but works pretty well on 3, 6, 9

    Quick test (using the above weighted hash):
    Code Ruby:
    result = Hash.new{|h,k| h[k] = 0}
    (1..10000).each do
      result[get_weighted_random(weighted)] += 1
    end
    #=> {:three=>5719, :one=>1574, :two=>2707}

    The results with weightings of 1, 2 & 3 are:
    Code Ruby:
    {:three=>6761, :one=>1619, :two=>1620}
    #See that the :one and :two where actually evenly weighted.


Tags for this Thread

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •