Related
def random_select(array, n)
result = []
n.times do
# I do not fully understand how this line below works or why. Thank you
result.push array[rand(array.length)]
end
result
end
You are probably confused by this part:
n.times do
result.push(array[rand(array.length)])
end
n.times says it should loop n times.
result.push says to basically "push" or "put" something in the array. For example:
a = []
a.push(1)
p a #=> [1]
In array[rand(array.length)] , rand(array.length) will produce a random number as an index for the array. Why? rand(n) produces a number from 0 to n-1. rand(5) will produce either 0,1,2,3 or 4, for example.
Arrays use 0-based indexing, so if you have an array, say a = ['x', 'y', 'z'], to access 'x' you do a[0], to access y you do a[1] and so on. If you want to access a random element from a, you do a[rand(array.length)], because a.length in this case is 3, and rand(3) will produce a number that is either 0, 1 or 2. 0 is the smallest index and 2 is the largest index of our example array.
So suppose we call this method:
random_select([6,3,1,4], 2)
Try to see this code from the inside out. When the code reaches this part:
result.push(array[rand(array.length)])
it will first execute array.length which will produce 4. It will then execute rand(array.length) or rand(4) which will get a number between 0 and 3. Then, it will execute array[rand(array.length)] or array(some_random_number_between_0_and_3) which will get you a random element from the array. Finally, result.push(all_of_that_code_inside_that_got_us_a_random_array_element) will put the random element from the array in the method (in our example, it will be either 6, 3, 1 or 4) in the results array. Then it will repeat this same process once again (remember, we told it to go 2 times through the iteration).
The code can be rewritten to be much simpler, using the block-form Array constructor:
def random_select(array, n)
Array.new(n) {array.sample}
end
This creates a new array of size n and fills it with random samples from the array.
Note that the above solution, like your sample code, selects from the entire array each time which allows duplicate selections. If you don't want any duplicate selections, it's even simpler, since it is the default behavior of Array#sample:
def random_select(array, n)
array.sample(n)
end
I was given this problem to solve with Ruby:
Compute the sum of cubes for a given range a through b. Write a method called sum_of_cubes to accomplish this task.
I wrote this:
def sum_of_cubes(a, b)
sum = 0
for x in a..b
c = x ** 3
end
sum += c
end
I got the value of the cube of b. What is wrong with this code? How can I solve this problem with a simple loop?
Thanks!
I would use Enumerable#reduce
def sum_of_cubes min, max
(min..max).reduce(0) { |a, b| a + b ** 3 }
end
A little explanation of what's happening here
We start with range (min..max) which is an Enumerable
irb> (1..3).is_a? Enumerable
=> true
Using the reduce instance method we get from Enumerable, we can use a block of code that gets called for each item in our (enumerable) range, and ultimately returns a single value.
The function name makes sense if you think "take my group of items and reduce them to a single value."
Here's our block
{ |a, b| a + b ** 3 }
We called reduce with 0 which is the initial value given to the block's a param
The return value of the block is passed to the block's a param on subsequent calls
Each item in the range will be passed to the block's b param
Let's step through and see how it works
(1..3).reduce(0) { |a, b| a + b ** 3 }
the first block call gets a=0 (initial value) and b=1 (first item in our range)
the return value of our block is 0 + 1 ** 3 or 1
the second block call gets a=1 (return value from the last call) and b=2 (the second item in our range)
the return value of our block is 1 + 2 ** 3 or 9
the third block call gets a=9 (return value from the last call) and b=3 (the third and last item in our range)
the return value of our block is 9 + 3 ** 3 or 36
the final return value of reduce is the last-called block's return value
in this case 36
You need to have sum += c inside the loop. And then return sum when done.
Here’s another way to calculate this. It doesn’t address your problems with your loop but I think it’s worth mentioning.
The sum of cubes of integers 13 + 23 + 33 + ... + n3 is given by the formula (n(n + 1)/2)2, so the sum of cubes of a given range min..max is therefore given by:
(max(max + 1)/2)2 - ((min-1)((min-1) + 1)/2)2
In code this could look like:
def sum_of_cubes_fixed min, max
lower = min - 1
(((max * (max + 1))/2) ** 2) - (((lower * (lower + 1))/2) ** 2)
end
This code avoids the loop, and so is O(1) rather than O(n) (almost – I’m hand waving a bit here, the time complexity of the multiplications and exponentiations will depend on the size of the numbers). For small sized ranges you won’t notice this, but for larger sizes the difference between this and the loop version becomes increasingly obvious. I haven’t done any strict benchmarks, but a quick test on my machine with the range 1 to 10,000,000 takes several seconds with the reduce method but is almost instantaneous with this method.
Normally I would just use reduce for something like this, but the structure of the task suggested that there might be a better way. With the help of Google I found the formula and came up with a more efficient solution (at least for large ranges).
(a..b).map{|i| i**3 }.inject(&:+) map and inject does the job, elegantly.
EDIT: Although it walks through the list twice ;)
I'm trying to improve my Ruby skills using the Project Euler series of questions and I'm wondering why this code does not work for this question: "Even Fibonacci numbers, Problem 2"
Each new term in the Fibonacci sequence is generated by adding the previous two terms. By starting with 1 and 2, the first 10 terms will be:
1, 2, 3, 5, 8, 13, 21, 34, 55, 89, ...
By considering the terms in the Fibonacci sequence whose values do not exceed four million, find the sum of the even-valued terms.
My code:
def fibo(n)
first, second, sequence = 0,1,[]
for e in n
first, second = second, first + second
sequence << e if e%2 == 0
end
sequence.inject(:+)
end
puts fibo(4000000)
Any help would be appreciated!
In the line:
for e in n
4,000,000 is being substituted for n, so you are saying:
for e in 4000000
which is not a valid statement - you cannot iterate on an integer.
If you would like to iterate through all the values from 0 to n, try:
for e in (0..n)
This iterates through the values in the range 0 to n.
However, there is a deeper problem here. It looks as though you want to iterate up to the value 4000000, but instead your code would iterate through the first 4000000 Fibonacci numbers, which is much more than you want. You may want to consider saying:
while second <= 4000000
I suggest you check out Ruby Koans if you're starting out with Ruby. It's a fun way of getting used to the ways of the language.
That said your code is not calculating Fibonacci correctly, it's not summing the Fibonacci numbers and also has some other errors (for e in n is not valid because n is not an Enumerator type). Fix it like this:
def fibo(n)
first, second, sum = 0, 1, 0
loop do
first, second = second, first + second
sum += second if second%2 == 0
break if second >= n
end
sum
end
Given a non-negative integer n and an arbitrary set of inequalities that are user-defined (in say an external text file), I want to determine whether n satisfies any inequality, and if so, which one(s).
Here is a points list.
n = 0: 1
n < 5: 5
n = 5: 10
If you draw a number n that's equal to 5, you get 10 points.
If n less than 5, you get 5 points.
If n is 0, you get 1 point.
The stuff left of the colon is the "condition", while the stuff on the right is the "value".
All entries will be of the form:
n1 op n2: val
In this system, equality takes precedence over inequality, so the order that they appear in will not matter in the end. The inputs are non-negative integers, though intermediary and results may not be non-negative. The results may not even be numbers (eg: could be strings). I have designed it so that will only accept the most basic inequalities, to make it easier for writing a parser (and to see whether this idea is feasible)
My program has two components:
a parser that will read structured input and build a data structure to store the conditions and their associated results.
a function that will take an argument (a non-negative integer) and return the result (or, as in the example, the number of points I receive)
If the list was hardcoded, that is an easy task: just use a case-when or if-else block and I'm done. But the problem isn't as easy as that.
Recall the list at the top. It can contain an arbitrary number of (in)equalities. Perhaps there's only 3 like above. Maybe there are none, or maybe there are 10, 20, 50, or even 1000000. Essentially, you can have m inequalities, for m >= 0
Given a number n and a data structure containing an arbitrary number of conditions and results, I want to be able to determine whether it satisfies any of the conditions and return the associated value. So as with the example above, if I pass in 5, the function will return 10.
They condition/value pairs are not unique in their raw form. You may have multiple instances of the same (in)equality but with different values. eg:
n = 0: 10
n = 0: 1000
n > 0: n
Notice the last entry: if n is greater than 0, then it is just whatever you got.
If multiple inequalities are satisfied (eg: n > 5, n > 6, n > 7), all of them should be returned. If that is not possible to do efficiently, I can return just the first one that satisfied it and ignore the rest. But I would like to be able to retrieve the entire list.
I've been thinking about this for a while and I'm thinking I should use two hash tables: the first one will store the equalities, while the second will store the inequalities.
Equality is easy enough to handle: Just grab the condition as a key and have a list of values. Then I can quickly check whether n is in the hash and grab the appropriate value.
However, for inequality, I am not sure how it will work. Does anyone have any ideas how I can solve this problem in as little computational steps as possible? It's clear that I can easily accomplish this in O(n) time: just run it through each (in)equality one by one. But what happens if this checking is done in real-time? (eg: updated constantly)
For example, it is pretty clear that if I have 100 inequalities and 99 of them check for values > 100 while the other one checks for value <= 100, I shouldn't have to bother checking those 99 inequalities when I pass in 47.
You may use any data structure to store the data. The parser itself is not included in the calculation because that will be pre-processed and only needs to be done once, but if it may be problematic if it takes too long to parse the data.
Since I am using Ruby, I likely have more flexible options when it comes to "messing around" with the data and how it will be interpreted.
class RuleSet
Rule = Struct.new(:op1,:op,:op2,:result) do
def <=>(r2)
# Op of "=" sorts before others
[op=="=" ? 0 : 1, op2.to_i] <=> [r2.op=="=" ? 0 : 1, r2.op2.to_i]
end
def matches(n)
#op2i ||= op2.to_i
case op
when "=" then n == #op2i
when "<" then n < #op2i
when ">" then n > #op2i
end
end
end
def initialize(text)
#rules = text.each_line.map do |line|
Rule.new *line.split(/[\s:]+/)
end.sort
end
def value_for( n )
if rule = #rules.find{ |r| r.matches(n) }
rule.result=="n" ? n : rule.result.to_i
end
end
end
set = RuleSet.new( DATA.read )
-1.upto(8) do |n|
puts "%2i => %s" % [ n, set.value_for(n).inspect ]
end
#=> -1 => 5
#=> 0 => 1
#=> 1 => 5
#=> 2 => 5
#=> 3 => 5
#=> 4 => 5
#=> 5 => 10
#=> 6 => nil
#=> 7 => 7
#=> 8 => nil
__END__
n = 0: 1
n < 5: 5
n = 5: 10
n = 7: n
I would parse the input lines and separate them into predicate/result pairs and build a hash of callable procedures (using eval - oh noes!). The "check" function can iterate through each predicate and return the associated result when one is true:
class PointChecker
def initialize(input)
#predicates = Hash[input.split(/\r?\n/).map do |line|
parts = line.split(/\s*:\s*/)
[Proc.new {|n| eval(parts[0].sub(/=/,'=='))}, parts[1].to_i]
end]
end
def check(n)
#predicates.map { |p,r| [p.call(n) ? r : nil] }.compact
end
end
Here is sample usage:
p = PointChecker.new <<__HERE__
n = 0: 1
n = 1: 2
n < 5: 5
n = 5: 10
__HERE__
p.check(0) # => [1, 5]
p.check(1) # => [2, 5]
p.check(2) # => [5]
p.check(5) # => [10]
p.check(6) # => []
Of course, there are many issues with this implementation. I'm just offering a proof-of-concept. Depending on the scope of your application you might want to build a proper parser and runtime (instead of using eval), handle input more generally/gracefully, etc.
I'm not spending a lot of time on your problem, but here's my quick thought:
Since the points list is always in the format n1 op n2: val, I'd just model the points as an array of hashes.
So first step is to parse the input point list into the data structure, an array of hashes.
Each hash would have values n1, op, n2, value
Then, for each data input you run through all of the hashes (all of the points) and handle each (determining if it matches to the input data or not).
Some tricks of the trade
Spend time in your parser handling bad input. Eg
n < = 1000 # no colon
n < : 1000 # missing n2
x < 2 : 10 # n1, n2 and val are either number or "n"
n # too short, missing :, n2, val
n < 1 : 10x # val is not a number and is not "n"
etc
Also politely handle non-numeric input data
Added
Re: n1 doesn't matter. Be careful, this could be a trick. Why wouldn't
5 < n : 30
be a valid points list item?
Re: multiple arrays of hashes, one array per operator, one hash per point list item -- sure that's fine. Since each op is handled in a specific way, handling the operators one by one is fine. But....ordering then becomes an issue:
Since you want multiple results returned from multiple matching point list items, you need to maintain the overall order of them. Thus I think one array of all the point lists would be the easiest way to do this.
I need to make a random list of permutations. The elements can be anything but assume that they are the integers 0 through x-1. I want to make y lists, each containing z elements. The rules are that no list may contain the same element twice and that over all the lists, the number of times each elements is used is the same (or as close as possible). For instance, if my elements are 0,1,2,3, y is 6, and z is 2, then one possible solution is:
0,3
1,2
3,0
2,1
0,1
2,3
Each row has only unique elements and no element has been used more than 3 times. If y were 7, then 2 elements would be used 4 times, the rest 3.
This could be improved, but it seems to do the job (Python):
import math, random
def get_pool(items, y, z):
slots = y*z
use_each_times = slots/len(items)
exceptions = slots - use_each_times*len(items)
if (use_each_times > y or
exceptions > 0 and use_each_times+1 > y):
raise Exception("Impossible.")
pool = {}
for n in items:
pool[n] = use_each_times
for n in random.sample(items, exceptions):
pool[n] += 1
return pool
def rebalance(ret, pool, z):
max_item = None
max_times = None
for item, times in pool.items():
if times > max_times:
max_item = item
max_times = times
next, times = max_item, max_times
candidates = []
for i in range(len(ret)):
item = ret[i]
if next not in item:
candidates.append( (item, i) )
swap, swap_index = random.choice(candidates)
swapi = []
for i in range(len(swap)):
if swap[i] not in pool:
swapi.append( (swap[i], i) )
which, i = random.choice(swapi)
pool[next] -= 1
pool[swap[i]] = 1
swap[i] = next
ret[swap_index] = swap
def plist(items, y, z):
pool = get_pool(items, y, z)
ret = []
while len(pool.keys()) > 0:
while len(pool.keys()) < z:
rebalance(ret, pool, z)
selections = random.sample(pool.keys(), z)
for i in selections:
pool[i] -= 1
if pool[i] == 0:
del pool[i]
ret.append( selections )
return ret
print plist([0,1,2,3], 6, 2)
Ok, one way to approximate that:
1 - shuffle your list
2 - take the y first elements to form the next row
4 - repeat (2) as long as you have numbers in the list
5 - if you don't have enough numbers to finish the list, reshuffle the original list and take the missing elements, making sure you don't retake numbers.
6 - Start over at step (2) as long as you need rows
I think this should be as random as you can make it and will for sure follow your criteria. Plus, you have very little tests for duplicate elements.
First, you can always randomly sort the list in the end, so let's not worry about making "random permutations" (hard); and just worry about 1) making permutations (easy) and 2) randomizing them (easy).
If you want "truly" random groups, you have to accept that randomization by nature doesn't really allow for the constraint of "even distribution" of results -- you may get that or you may get a run of similar-looking ones. If you really want even distribution, first make the sets evenly distributed, and then randomize them as a group.
Do you have to use each element in the set x evenly? It's not clear from the rules that I couldn't just make the following interpretation:
Note the following: "over all the lists, the number of times each elements is used is the same (or as close as possible)"
Based on this criteria, and the rule that z < x*, I postulate that you can simply enumerate all the items over all the lists. So you automatically make y list of the items enumerated to position z. Your example doesn't fulfill the rule above as closely as my version will. Using your example of x={0,1,2,3} y=6 and z=2, I get:
0,1 0,1 0,1 0,1 0,1 0,1
Now I didn't use 2 or 3, but you didn't say I had to use them all. If I had to use them all and I don't care to be able to prove that I am "as close as possible" to even usage, I would just enumerate across all the items through the lists, like this:
0,1 2,3 0,1 2,3 0,1 2,3
Finally, suppose I really do have to use all the elements. To calculate how many times each element can repeat, I just take (y*z)/(count of x). That way, I don't have to sit and worry about how to divide up the items in the list. If there is a remainder, or the result is less than 1, then I know that I will not get an exact number of repeats, so in those cases, it doesn't much matter to try to waste computational energy to make it perfect. I contend that the fastest result is still to just enumerate as above, and use the calculation here to show why either a perfect result was or wasn't achieved. A fancy algorithm to extract from this calculation how many positions will be duplicates could be achieved, but "it's too long to fit here in the margin".
*Each list has the same z number of elements, so it will be impossible to make lists where z is greater than x and still fulfill the rule that no list may contain the same element twice. Therefore, this rule demands that z cannot be greater than x.
Based on new details in the comments, the solution may simply be an implementation of a standard random permutation generation algorithm. There is a lengthy discussion of random permutation generation algorithms here:
http://www.techuser.net/randpermgen.html
(From Google search: random permutation generation)
This works in Ruby:
# list is the elements to be permuted
# y is the number of results desired
# z is the number of elements per result
# equalizer keeps track of who got used how many times
def constrained_permutations list, y, z
list.uniq! # Never trust the user. We want no repetitions.
equalizer = {}
list.each { |element| equalizer[element] = 0 }
results = []
# Do this until we get as many results as desired
while results.size < y
pool = []
puts pool
least_used = equalizer.each_value.min
# Find how used the least used element was
while pool.size < z
# Do this until we have enough elements in this resultset
element = nil
while element.nil?
# If we run out of "least used elements", then we need to increment
# our definition of "least used" by 1 and keep going.
element = list.shuffle.find do |x|
!pool.include?(x) && equalizer[x] == least_used
end
least_used += 1 if element.nil?
end
equalizer[element] += 1
# This element has now been used one more time.
pool << element
end
results << pool
end
return results
end
Sample usage:
constrained_permutations [0,1,2,3,4,5,6], 6, 2
=> [[4, 0], [1, 3], [2, 5], [6, 0], [2, 5], [3, 6]]
constrained_permutations [0,1,2,3,4,5,6], 6, 2
=> [[4, 5], [6, 3], [0, 2], [1, 6], [5, 4], [3, 0]]
enter code here
http://en.wikipedia.org/wiki/Fisher-Yates_shuffle