how do i combine variables? - ruby

im making a program and i need to combine a lot of variables, most of them strings but i have some int, by doing this
name = "#{variable1}#{variable2}"
name2 = "#{variable2}#{variable1}"
it´s a simple example with just two variables but thats the idea, what im trying to make. i am doing all the possibilities one by one, even when is more than two variables but there are many combinations. Is there an easy way to do it or i have to do it one by one?Also, do i need to write the quotation marks separately or that way is fine?

Is this what you had in mind?
variable1 = "cat"
variable2 = 9
variable3 = "lives"
arr = [variable1, variable2, variable3]
#=> ["cat", 9, "lives"]
arr.join
#=> "cat9lives"

Put all or some of these variables into an array which will produce the combinations easier.
s1 = 'a'
s2 = 'b'
s3 = 'c'
n = 8
[s1, s2, s3, n].combination(3).map(&:join)
=> ["abc", "ab8", "ac8", "bc8"]
Above example assumes that you will pick any of 3 variables from the array and calculate the combinations. You may want to adjust that number to meet your needs.

The whole idea of programming is not doing all possibilities one by one. "there are many combinations": they look like permutations to me. If that is the case:
var1 = "aa"
var2 = "bb"
var3 = 2
res = [var1, var2, var3].permutation.map{|perm| perm.join}
p res #=> ["aabb2", "aa2bb", "bbaa2", "bb2aa", "2aabb", "2bbaa"]

Related

How to make a number argument a variable?

How do I make a number argument a variable?
For example:
Snippet 1:
a=1
a_7 = a+6
alphabet = "ABCDEFGHIJKLMNOPQRSTUVQXYZ"
letter_7 = alphabet.slice[a_7..a_7]
Snippet 2:
alphabet = "ABCDEFGHIJKLMNOPQRSTUVQXYZ"
letter_7 = alphabet.slice[7..7]
I would like to make snippet 1 have the same outcome as snippet 2, with a variable as the arguments within slice action. Is there a way to do this?
So your issue come from the fact that you are using the slice method without any arguments. You can not use [] with the slice method. To make this work, you need to change [] to ()
letter_7 = alphabet.slice(7..7)
This will actually return H as the result, because arrays index start at 0, so to get the 7th letter, you will need to slice at index 6.
letter_7 = alphabet.slice(6..6) #=> 'G'
Or, you can just use the [] method on the string itself.
letter_7 = alphabet[6] #=> 'G'
Of course, you can replace the index values with variables, as long as the variables are set to integers.
a = 6
letter_7 = alphabet[a] #=> 'G'

Ruby: evaluate string with dynamic binding of variables

I have a database of "formulas" stored as strings. Let's assume for simplicity, that each formula contains 2 variables denoted by a and b, and that the formulas are all wellformed and it is ensured that it consists only of characters from the set ()ab+-*.
At runtime, formulas are fetched from this database, and from another source, numeric values for a and b are fetched, and the formulas are evaluated. The evaluation can be programmed like this:
# This is how it works right now
formula = fetch_formula(....)
a = fetch_left_arg(....)
b = fetch_right_arg(....)
result = eval(formula)
This design works, but I'm not entirely happy with it. It requires that my program names the free variables exactly the same as they are named in the formula, which is ugly.
If my "formula" would not be a string, but a Proc object or Lambda which accepts two parameters, I could do something like
# No explicitly named variables
result = fetch_proc(...).call(fetch_left_arg(....),fetch_right_arg(....))
but unfortunately, the formulas have to be strings.
I tried to experiment in the following way: What if the method, which fetches the formula from the database, would wrap the string into something, which behaves like a block, and where I could pass parameters to it?
# This does not work of course, but maybe you get the idea:
block_string = "|a,b| #{fetch_formula(....)}"
Of course I can't eval such a block_string, but is there something similar which I could use? I know that instance_eval can pass parameters, but what object should I apply it to? So this is perhaps not an option either....
This is very nasty approach, but for simple formulas you’ve mentioned it should work:
▶ formula = 'a + b'
▶ vars = formula.scan(/[a-z]+/).uniq.join(',') # getting vars names
#⇒ "a,b"
▶ pr = eval("proc { |#{vars}| #{formula} }") # preparing proc
▶ pr.call 3, 5
#⇒ 8
Here we rely on the fact, that parameters are passed to the proc in the same order, as they appear in the formula.
If I get your question correctly, it is something that I have done recently, and is fairly easy. Given a string:
s = "{|x, y| x + y}"
You can create a proc by doing:
eval("Proc.new#{s}")
One way to avoid creating the variables in the local scope could be to use a Binding:
bind = binding
formula = fetch_formula(....)
bind.local_variable_set :a, fetch_left_arg(....)
bind.local_variable_set :b, fetch_right_arg(....)
result = bind.eval(formula)
The variables a and b now only exist in the binding, and do not pollute the rest of your code.
You can create a lambda from string, as shown below:
formula = "a + b"
lambda_template = "->(a,b) { %s }"
formula_lambda = eval(lambda_template % formula)
p formula_lambda.call(1,2)
#=> 3

Change variable passed in a method [duplicate]

This question already has answers here:
'pass parameter by reference' in Ruby?
(6 answers)
Closed 8 years ago.
How can I change the contents of a variable using a method? Maybe I'm not saying this correctly. What is a way to get the reference to a variable like in C? Example:
// main stuff
int gorilla = 29;
makeMeABanana(&gorilla);
void makeMeABanana(int *gorilla) { }
How can I do something like this in Ruby?
You should not do this - you're just porting techniques that are fully appropriate to C to Ruby, where they are no longer appropriate. There are several fancy ways around this (eg using a Proc closed over your calling namespace, or eval) but they are usually inappropriate in Ruby unless you know precisely what you're doing.
Recently on the ruby-talk mailing list, someone asked about writing a swap function where swap(a,b) would swap the values of the variables "a" and "b". Normally this cannot be done in Ruby because the swap function would have no reference to the binding of the calling function.
However, if we explictly pass in the binding, then it is possible to write a swap-like function. Here is a simple attempt:
def swap(var_a, var_b, vars)
old_a = eval var_a, vars
old_b = eval var_b, vars
eval "#{var_a} = #{old_b}", vars
eval "#{var_b} = #{old_a}", vars
end
a = 22
b = 33
swap ("a", "b", binding)
p a # => 33
p b # => 22
This actually works! But it has one big drawback. The old values of "a" and "b" are interpolated into a string. As long as the old values are simple literals (e.g. integers or strings), then the last two eval statements will look like: eval "a = 33", vars". But if the old values are complex objects, then the eval would look like eval "a = #", vars. Oops, this will fail for any value that can not survive a round trip to a string and back.
Referred from : http://onestepback.org/index.cgi/Tech/Ruby/RubyBindings.rdoc
Integers are objects, with an id, like everything else in Ruby. They are implemented like this:
p (0..10).map{|n| n.object_id}
#=>[1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21]
All other objects have even object_id numbers. There is no way to change 7 (object_id 15) into something else.

Combine array of array into all possible combinations, forward only, in Ruby

I have an array of arrays, like so:
[['1','2'],['a','b'],['x','y']]
I need to combine those arrays into a string containing all possible combinations of all three sets, forward only. I have seen lots of examples of all possible combinations of the sets in any order, that is not what I want. For example, I do not want any of the elements in the first set to come after the second set, or any in the third set to come before the first, or second, and so on. So, for the above example, the output would be:
['1ax', '1ay', '1bx', '1by', '2ax', '2ay', '2bx', '2by']
The number of arrays, and length of each set is dynamic.
Does anybody know how to solve this in Ruby?
Know your Array#product:
a = [['1','2'],['a','b'],['x','y']]
a.first.product(*a[1..-1]).map(&:join)
Solved using a recursive, so-called "Dynamic Programming" approach:
For n-arrays, combine the entries of the first array with each result on the remaining (n-1) arrays
For a single array, the answer is just that array
In code:
def variations(a)
first = a.first
if a.length==1 then
first
else
rest = variations(a[1..-1])
first.map{ |x| rest.map{ |y| "#{x}#{y}" } }.flatten
end
end
p variations([['1','2'],['a','b'],['x','y']])
#=> ["1ax", "1ay", "1bx", "1by", "2ax", "2ay", "2bx", "2by"]
puts variations([%w[a b],%w[M N],['-'],%w[x y z],%w[0 1 2]]).join(' ')
#=> aM-x0 aM-x1 aM-x2 aM-y0 aM-y1 aM-y2 aM-z0 aM-z1 aM-z2 aN-x0 aN-x1 aN-x2
#=> aN-y0 aN-y1 aN-y2 aN-z0 aN-z1 aN-z2 bM-x0 bM-x1 bM-x2 bM-y0 bM-y1 bM-y2
#=> bM-z0 bM-z1 bM-z2 bN-x0 bN-x1 bN-x2 bN-y0 bN-y1 bN-y2 bN-z0 bN-z1 bN-z2
You could also reverse the logic, and with care you should be able to implement this non-recursively. But the recursive answer is rather straightforward. :)
Pure, reduce with product:
a = [['1','2'],['a','b'],['x','y']]
a.reduce() { |acc, n| acc.product(n).map(&:flatten) }.map(&:join)
# => ["1ax", "1ay", "1bx", "1by", "2ax", "2ay", "2bx", "2by"]

Ruby 1.9 bug? -- Array.permutation

While trying problem 41 from the Euler Project, I ran across what seems to be a bug in the Ruby 1.9 implementation of Array.permutation. Here's the problem code isolated:
n = 4
slice = '987654321'.chars.to_a[-n..-1]
puts "slice = #{slice.join}"
slice.permutation(n) {|perm| puts perm.join}
slice2 = slice.dup
puts "slice2 = #{slice2.join}"
slice2.permutation(n) {|perm| puts perm.join}
slice3 = []
(0...n).each {|i| slice3[i] = slice[i]}
puts "slice3 = #{slice3.join}"
slice3.permutation(n) {|perm| puts perm.join}
My output for slice and slice2 is:
slice = 4321
9876
9867
9786
9768
9687
...
However, slice3 comes out right, with the digits 1 to 4 being permuted. Also n = 4 is the first value that has this problem. When I set n = 3, I get the expected output. Is this a bug, or am I mis-coding something? A quick Google search didn't turn up anything.
It is a known bug which is fixed in 1.9.2p136 and newer.
Easiest way around it, besides updating to a more recent Ruby, is to insure your array is not "shared", either by building a new one (like your slice3), or simply "modifying" it, e.g. slice += [].

Resources