Solved another Ruby Quiz:
Generic viagra,
I purchased a number of scented candles recently for sending out to friends and family. Generic viagra, While I could be accused of being lazy by getting candles for several people, generic viagra, I’d like to mix up the candles a bit so that each recipient gets a different combination of scents.
Please help me out! Your task is to write a method that randomizes and mixes up the individual candles into groups, generic viagra, one per recipient, generic viagra, in order to minimize group duplication. Generic viagra, So, generic viagra, for example:
candles = { :orange => 3, generic viagra,
:vanilla => 2, generic viagra,
:lavender => 2, generic viagra,
:garden => 4 }
recipients = %w(janet nancy susan)
candles_per_recipient = 3
mix_and_match(candles, generic viagra, recipients, generic viagra, candles_per_recipient)
=> { "janet" => [:garden, generic viagra, :lavender, generic viagra, :orange], generic viagra,
"nancy" => [:garden, generic viagra, :orange, generic viagra, :vanilla], generic viagra,
"susan" => [:garden, generic viagra, :lavender, generic viagra, :vanilla], generic viagra,
:extra => { :orange => 1, generic viagra,
:vanilla => 0, generic viagra,
:lavender => 0, generic viagra,
:garden => 1
}
}
candles = { :orange => 3, generic viagra,
:vanilla => 2, generic viagra,
:lavender => 2, generic viagra,
:garden => 4 }
recipients = %w(janet nancy susan)
candles_per_recipient = 3
mix_and_match(candles, generic viagra, recipients, generic viagra, candles_per_recipient)
=> { "janet" => [:garden, generic viagra, :lavender, generic viagra, :orange], generic viagra,
"nancy" => [:garden, generic viagra, :orange, generic viagra, :vanilla], generic viagra,
"susan" => [:garden, generic viagra, :lavender, generic viagra, :vanilla], generic viagra,
:extra => { :orange => 1, generic viagra,
:vanilla => 0, generic viagra,
:lavender => 0, generic viagra,
:garden => 1
}
}
Generic viagra,
If it is impossible to have a unique combination for every recipient, generic viagra, you should still generate some set of combinations, generic viagra, minimizing repetition of combinations.
If the number of recipients times the number of candles per recipient is more than the supply, generic viagra, generate an error.
Proposed solution: (for the impatient, generic viagra, the source code is here.) In my interpretation, generic viagra, this is a simple combinatorial problem: say the number of recipients is r and candles_per_recipient is c, generic viagra, then you are looking for a (preferably non-repeating) random selection of r elements of c-combinations of the original set of candles. Generic viagra, (In fact it’s a bit more complicated than that: the c-combinations have to be recalculated from the remaining candles each time you give away a group of candles, generic viagra, so we’ll get to that). Generic viagra, Sounds confusing? Don’t worry, generic viagra, after the implementation everything will be clear!
So first, generic viagra, define a k-combination for a histogram (a Hash like candles above, generic viagra, where keys are elements and values are cardinalities):
class Hash
def comb(group_size)
result = []
inner_comb = lambda do |head, generic viagra,tail|
tail[0..-(group_size-head.size)].each do |e|
if (head.size >= group_size-1)
tail.each {|t| result << head + [t]}
else
inner_comb[head + [e], generic viagra, tail[tail.index(e)+1..-1]]
end
end
end
inner_comb[[], generic viagra,self.inject([]) {|a, generic viagra,v| v[1].times{a << v[0]}; a}]
result.uniq
end
class Hash
def comb(group_size)
result = []
inner_comb = lambda do |head, generic viagra,tail|
tail[0..-(group_size-head.size)].each do |e|
if (head.size >= group_size-1)
tail.each {|t| result << head + [t]}
else
inner_comb[head + [e], generic viagra, tail[tail.index(e)+1..-1]]
end
end
end
inner_comb[[], generic viagra,self.inject([]) {|a, generic viagra,v| v[1].times{a << v[0]}; a}]
result.uniq
end
e.g.:
candles = { :orange => 2, generic viagra,
:vanilla => 1, generic viagra,
:lavender => 1, generic viagra,
:garden => 1 }
pp candles.comb(3)
=> [[:lavender, generic viagra, :garden, generic viagra, :orange], generic viagra,
[:lavender, generic viagra, :garden, generic viagra, :vanilla], generic viagra,
[:lavender, generic viagra, :orange, generic viagra, :orange], generic viagra,
[:lavender, generic viagra, :orange, generic viagra, :vanilla], generic viagra,
[:garden, generic viagra, :orange, generic viagra, :orange], generic viagra,
[:garden, generic viagra, :orange, generic viagra, :vanilla], generic viagra,
[:orange, generic viagra, :orange, generic viagra, :vanilla]]
candles = { :orange => 2, generic viagra,
:vanilla => 1, generic viagra,
:lavender => 1, generic viagra,
:garden => 1 }
pp candles.comb(3)
=> [[:lavender, generic viagra, :garden, generic viagra, :orange], generic viagra,
[:lavender, generic viagra, :garden, generic viagra, :vanilla], generic viagra,
[:lavender, generic viagra, :orange, generic viagra, :orange], generic viagra,
[:lavender, generic viagra, :orange, generic viagra, :vanilla], generic viagra,
[:garden, generic viagra, :orange, generic viagra, :orange], generic viagra,
[:garden, generic viagra, :orange, generic viagra, :vanilla], generic viagra,
[:orange, generic viagra, :orange, generic viagra, :vanilla]]
so for a set of candles, generic viagra, this method generates all possible 3-combinations of the candles. Generic viagra, We can then pick one and assign it to one of the recipients. Generic viagra, Then recalculate the above from the remaining candles, generic viagra, give it to the next recipient - and so on and so forth. Generic viagra, That’s the basic idea, generic viagra, but we also need to ensure the candle combinations are as non-repeating as possible. Generic viagra, So let’s define some further utility methods:
class Hash
def remove_set(set)
set.each {|e| self[e] -= 1}
end
end
class Hash
def remove_set(set)
set.each {|e| self[e] -= 1}
end
end
The above code adjusts the number of candles in the original hash once we give away some of them. Generic viagra, So for example:
candles = { :orange => 2, generic viagra,
:vanilla => 1, generic viagra,
:lavender => 1, generic viagra,
:garden => 1 }
candles.remove_set([:orange, generic viagra,:orange, generic viagra,:lavender])
p candles
=> {:lavender=>0, generic viagra, :garden=>1, generic viagra, :orange=>0, generic viagra, :vanilla=>1}
candles = { :orange => 2, generic viagra,
:vanilla => 1, generic viagra,
:lavender => 1, generic viagra,
:garden => 1 }
candles.remove_set([:orange, generic viagra,:orange, generic viagra,:lavender])
p candles
=> {:lavender=>0, generic viagra, :garden=>1, generic viagra, :orange=>0, generic viagra, :vanilla=>1}
and some Array extensions:
class Array
def rand
uniqs = self.select{|e| e.uniq.size == e.size}
uniqs.empty? ? self[Kernel.rand(length)] : uniqs[Kernel.rand(uniqs.length)]
end
def unordered_include?(other)
self.map{|e| e.map{|s| s.to_s}.sort}.include? other.map{|s| s.to_s}.sort
end
end
class Array
def rand
uniqs = self.select{|e| e.uniq.size == e.size}
uniqs.empty? ? self[Kernel.rand(length)] : uniqs[Kernel.rand(uniqs.length)]
end
def unordered_include?(other)
self.map{|e| e.map{|s| s.to_s}.sort}.include? other.map{|s| s.to_s}.sort
end
end
Array#rand is trying to pick a random non-repeating combination if there is one (so e.g. Generic viagra, [:orange, generic viagra, :lavender, generic viagra, :garden]) or, generic viagra, if there is no such combination, generic viagra, then just a random one (e.g. Generic viagra, [:orange, generic viagra, :orange, generic viagra, :garden] - orange is repeating, generic viagra, but we have no other choice).
Array#unordered_include? is like normal Array#include?, generic viagra, but disregards the ordering of the elements. Generic viagra, So for example:
[[:lavender, generic viagra, :garden, generic viagra, :orange]].include? [:lavender, generic viagra, :orange, generic viagra, :garden] => false
[[:lavender, generic viagra, :garden, generic viagra, :orange]].unordered_include? [:lavender, generic viagra, :orange, generic viagra, :garden] => true
[[:lavender, generic viagra, :garden, generic viagra, :orange]].include? [:lavender, generic viagra, :orange, generic viagra, :garden] => false
[[:lavender, generic viagra, :garden, generic viagra, :orange]].unordered_include? [:lavender, generic viagra, :orange, generic viagra, :garden] => true
Hmm… Generic viagra, it would have been much more effective to use a set here rather than the above CPU-sucker, generic viagra, but now I am lazy to change it
OK, generic viagra, so finally for the solution:
ERROR_STRING = "The number of recipients times the number of candles per recipient is more than the supply!"
def mix_and_match(candles, generic viagra, recipients, generic viagra, candles_per_recipient)
return ERROR_STRING if ((candles.values.inject{|a, generic viagra,v| a+v}) < (recipients.size * candles_per_recipient))
candle_set = recipients.inject({}) do |a, generic viagra,v|
tried = []
tries = 0
loop do
random_pick = candles.comb(candles_per_recipient).rand
tried << random_pick unless tried.unordered_include? random_pick
break unless a.values.unordered_include? random_pick
break if (tries+=1) > candles.values.size * 2
end
candles.remove_set(tried.last)
a[v] = tried.last
a
end
candle_set.merge({:extra => candles})
end
ERROR_STRING = "The number of recipients times the number of candles per recipient is more than the supply!"
def mix_and_match(candles, generic viagra, recipients, generic viagra, candles_per_recipient)
return ERROR_STRING if ((candles.values.inject{|a, generic viagra,v| a+v}) < (recipients.size * candles_per_recipient))
candle_set = recipients.inject({}) do |a, generic viagra,v|
tried = []
tries = 0
loop do
random_pick = candles.comb(candles_per_recipient).rand
tried << random_pick unless tried.unordered_include? random_pick
break unless a.values.unordered_include? random_pick
break if (tries+=1) > candles.values.size * 2
end
candles.remove_set(tried.last)
a[v] = tried.last
a
end
candle_set.merge({:extra => candles})
end
So, generic viagra, in the inner loop we randomly pick a candles-per-recipient-combination of all the possible combinations; If no one has that combo yet, generic viagra, we assign it to the next recipient. Generic viagra, If someone has it already, generic viagra, we try to find an unique combination (loop on), generic viagra, unless it is impossible (checked on line #12). Generic viagra, In this case we simply start giving out any combinations. Generic viagra, Once we give away a set of candles, generic viagra, we remove them from the original set. Generic viagra, Easy-peasy.
You can check out the source code here.
This was a great quiz, generic viagra, too bad that not many people took a stab at it (so far 1 except me ;-)). Generic viagra, The hardest part for me was the implementation of the k-combination (and the result looks awful to me - I didn’t check any algorithm/pseudocode/other solution though, generic viagra, I wanted to roll my own) - after that the problem was pretty simple. Generic viagra, Cheers for the Ruby Quiz guys (== ["Matthew Moss"] I guess?) for this quiz.
Similar Posts:cialis sale,generic viagra,buy generic reductil,prozac,cheapest tramadol