Variable assignment confusion - ruby-on-rails

I'm stuck on a homework problem, and found a solution by looking at someone's work. Problem is I don't understand it. Here's the code
ordering, #title_header = {:order => :title}, 'hilite'
What is happening to 'ordering' in this case? I tried googling to see if that's a method, but couldn't find anything.

What you're seeing is actually list expansion. Ruby can do the following:
a, b = 1, 2
This is essentially the same as:
a = 1
b = 2
I'll leave the rest for you to figure out.

This is "parallel assignment".
Parallel assignment in Ruby is what happens when there is more than 1 lvalue (i.e., value on the left-hand side of the equals sign) and/or more than 1 rvalue (value on the right-hand side of the equals sign).
To understand parallel assignment, there are various cases to consider.
Case #1: One value on the left, multiple values on the right
The first, simplest case is when there is 1 lvalue and multiple rvalues. For example:
> a = 1, 2
> a
=> [1, 2]
All that's happening is the right-hand comma-separated list of values is converted into an array and assigned to the left-hand variable.
Case #2: Multiple values on the left, the same number of values on the right
The second case is when there are the same number of lvalues and rvalues. For example:
> a,b = 'foo', 'bar'
> a
=> "foo"
> b
=> "bar"
This is also pretty straightforward -- you simply evaluate each item on the right hand, then assign it to its corresponding variable on the left-hand side, in order.
Case #3: Multiple values on the left, one value on the right -- but it's an array
The third case is when the rvalue is an array, and that array's elements are distributed (or "expanded") among multiple lvalues. For example:
> a, b = ['foo', 'bar']
> a
=> "foo"
> b
=> "bar"
This is effectively the same as case #2, above, except in this case explicitly employing array syntax.
Case #4: More values on the left than on the right
The fourth case is when there are multiple values on both sides, and there are more lvalues than rvalues. For example:
> a, b, c = 'foo', 'bar' # Note only 2 values on the right
> a
=> 'foo'
> b
=> 'bar'
> c
=> nil
As you can see, Ruby did the best it could to distribute the values, but ran out of them and was forced to assign nil to the last variable on the left.
Case #5: More values on the right than on the left
The fifth case is when there are multiple values on both sides, and there are fewer lvalues than rvalues. For example:
> a, b = 'foo', 'bar', 'baz' # Note only 2 values on the left
> a
=> 'foo'
> b
=> 'bar'
Again, Ruby did the best it could to distribute the values, but had too many to parcel out, and was forced to send the right-most value ("baz") into the ether.
Case #6+: Splatting
Note in the case above, we lost the last value. However it is actually possible to capture any such excess values and gather them into an array, using a related operator called the "splat" operator (which consists of an asterisk in front of the variable, as in *my_var). You can do a number of useful things with this "splat" operator, but so as not to overload this answer too much, it's probably better to go elsewhere to look at examples of it in action. E.g., this blog post lists several variant uses.
Note: Swapping without a temp variable
One nice aspect of this parallel assignment facility is that you can swap values conveniently.
To swap values without parallel assignment, you might write something like this:
> a = 'foo'
> b = 'bar'
> temp = a # Introduce a temp variable
> a = b
> b = temp
> a
=> "bar"
> b
=> "foo"
But with parallel assignment, you can simply rely on Ruby to implicitly handle the swapping for you:
> a = 'foo'
> b = 'bar'
> b, a = a, b
> a
=> "bar"
> b
=> "foo"

Related

Casting a value in Lua table, not a link

I have simplified my code so you can have a better understanding:
x = {}
x["foo"]=1
a = {}
a[1]=x
x["foo"]=2
a[2]=x
print(a[1]["foo"])
print(a[2]["foo"])
The result is:
2
2
Or I was expecting:
1
2
I understant that a[1] is directing at the adress of the table x["foo"]. Then, when I change the value of this table, the variable a[1] points to the new value.
How can I tell Lua that I want to assign the VALUE and not link to and adress?
And just another thing: if x is a "simple" variable, not an array, the value is passed:
y = {}
x = 1
a = {}
a[1] = x
x = 2
a[2] = x
print(a[1])
print(a[2])
returns
1
2
The Lua manual, last but one paragraph of §2.1, says:
Tables, functions, threads, and (full) userdata values are objects: variables do not actually contain these values, only references to them. Assignment, parameter passing, and function returns always manipulate references to such values; these operations do not imply any kind of copy.

Reading defined amount of numbers w/o array

Often in my tasks I've got to read previously defined amount of numbers in line and of course I know how they are separated. For example, let's say it'd be two coordinates separated with space. Here is what I actually do to read this line:
line = gets.split(' ').map(&:to_i)
It's fine, but I either have to call line[0] .. line[1] or add two lines for a = line[0] ...
Is there any way to read defined amount of numbers and assign them to variables, not an array?
EDIT/TL:DR: In the other words: I'm looking for Ruby's scanf("%d %d", &x, &y);
Just do this:
x, y = gets.split(' ').map(&:to_i)
puts "x: #{x}"
puts "y: #{y}"
If you do not know how many values will be in the string you cannot assign each value to a local variable. That's because you cannot use parallel assignment (see my comment on #K's answer) and, since Ruby v1.9, you cannot define local variables dynamically (e.g, eval("x=1") doesn't work).
You can assign the values to instance variables dynamically, like so:
arr = gets.chomp.split(/\s+/)
or
arr = gets.split(/\s+/).map(&:to_i)
depending on your needs.
Suppose
arr = [1, 2, 3, 4]
Then:
arr.each_with_index { |x,i| instance_variable_set("#my_var#{i}", x) }
instance_variable_get(:#my_var0) #=> 1
instance_variable_get(:#my_var1) #=> 2
instance_variable_get(:#my_var2) #=> 3
instance_variable_get(:#my_var3) #=> 4
But why would you want to do this?
Edit:
You know that gets will return a string that contains two substrings representing integers, separated by one or more spaces, and you wish to assign those two integers to variables x and y.
I expect you don't mind if unnamed temporary arrays are created, you just don't want any named arrays, such as:
arr = gets.map(&:to_i)
x,y = arr
If, however, you want to do this without creating any arrays, this might work:
s = gets #=> "1 -2\n"
x = s[/(-?\d+)\s/,1].to_i #=> 1
y = s[/\s(-?\d+)/,1].to_i #=> -2
I say "might" because I don't know if Ruby is creating any arrays in the background for her own use.
Alternatively, you could use positive lookarounds and no capture groups:
x = s[/-?\d+(?=\s)/].to_i #=> 1
y = s[/(?<=\s)-?\d+/].to_i #=> -2

lua - table.concat with string keys

I'm having a problem with lua's table.concat, and suspect it is just my ignorance, but cannot find a verbose answer to why I'm getting this behavior.
> t1 = {"foo", "bar", "nod"}
> t2 = {["foo"]="one", ["bar"]="two", ["nod"]="yes"}
> table.concat(t1)
foobarnod
> table.concat(t2)
The table.concat run on t2 provides no results. I suspect this is because the keys are strings instead of integers (index values), but I'm not sure why that matters.
I'm looking for A) why table.concat doesn't accept string keys, and/or B) a workaround that would allow me to concatenate a variable number of table values in a handful of lines, without specifying the key names.
Because that's what table.concat is documented as doing.
Given an array where all elements are strings or numbers, returns table[i]..sep..table[i+1] ··· sep..table[j]. The default value for sep is the empty string, the default for i is 1, and the default for j is the length of the table. If i is greater than j, returns the empty string.
Non-array tables have no defined order so table.concat wouldn't be all that helpful then anyway.
You can write your own, inefficient, table concat function easily enough.
function pconcat(tab)
local ctab, n = {}, =1
for _, v in pairs(tab) do
ctab[n] = v
n = n + 1
end
return table.concat(ctab)
end
You could also use next manually to do the concat, etc. yourself if you wanted to construct the string yourself (though that's probably less efficient then the above version).

Why does Lua's length (#) operator return unexpected values?

Lua has the # operator to compute the "length" of a table being used as an array.
I checked this operator and I am surprised.
This is code, that I let run under Lua 5.2.3:
t = {};
t[0] = 1;
t[1] = 2;
print(#t); -- 1 aha lua counts from one
t[2] = 3;
print(#t); -- 2 tree values, but only two are count
t[4] = 3;
print(#t); -- 4 but 3 is mssing?
t[400] = 400;
t[401] = 401;
print(#t); -- still 4, now I am confused?
t2 = {10, 20, nil, 40}
print(#t2); -- 4 but documentations says this is not a sequence?
Can someone explain the rules?
About tables in general
(oh, can't you just give me an array)
In Lua, a table is the single general-purpose data structure. Table keys can be of any type, like number, string, boolean. Only nil keys aren't allowed.
Whether tables can or can't contain nil values is a surprisingly difficult question which I tried to answer in depth here. Let's just assume that setting t[k] = nil should be the observably the same as never setting k at all.
Table construction syntax (like t2 = {10, 20, nil, 40}) is a syntactic sugar for creating a table and then setting its values one by one (in this case: t2 = {}, t2[1] = 10, t2[2] = 20, t2[3] = nil, t2[4] = 40).
Tables as arrays
(oh, from this angle it really looks quite arrayish)
As tables are the only complex data structure in Lua, the language (for convenience) provides some ways for manipulating tables as if they were arrays.
Notably, this includes the length operator (#t) and many standard functions, like table.insert, table.remove, and more.
The behavior of the length operator (and, in consequence, the mentioned utility functions) is only defined for array-like tables with a particular set of keys, so-called sequences.
Quoting the Lua 5.2 Reference manual:
the length of a table t is only defined if the table is a sequence, that is, the set of its positive numeric keys is equal to {1..n} for some integer n
As a result, the behavior of calling #t on a table not being a sequence at that time, is undefined.
It means that any result could be expected, including 0, -1, or false, or an error being raised (unrealistic for the sake of backwards compatibility), or even Lua crashing (quite unrealistic).
Indirectly, this means that the behavior of utility functions that expect a sequence is undefined if called with a non-sequence.
Sequences and non-sequences
(it's really not obvious)
So far, we know that using the length operator on tables not being sequences is a bad idea. That means that we should either do that in programs that are written in a particular way, that guarantees that those tables will always be sequences in practice, or, in case we are provided with a table without any assumptions about their content, we should dynamically ensure they are indeed a sequence.
Let's practice. Remember: positive numeric keys have to be in the form {1..n}, e.g. {1}, {1, 2, 3}, {1, 2, 3, 4, 5}, etc.
t = {}
t[1] = 123
t[2] = "bar"
t[3] = 456
Sequence. Easy.
t = {}
t[1] = 123
t[2] = "bar"
t[3] = 456
t[5] = false
Not a sequence. {1, 2, 3, 5} is missing 4.
t = {}
t[1] = 123
t[2] = "bar"
t[3] = 456
t[4] = nil
t[5] = false
Not a sequence. nil values aren't considered part of the table, so again we're missing 4.
t = {}
t[1] = 123
t[2] = "bar"
t[3.14] = 456
t[4] = nil
t[5] = false
Not a sequence. 3.14 is positive, but isn't an integer.
t = {}
t[0] = "foo"
t[1] = 123
t[2] = "bar"
Sequence. 0 isn't counted for the length and utility functions will ignore it, but this is a valid sequence. The definition only gives requirements about positive number keys.
t = {}
t[-1] = "foo"
t[1] = 123
t[2] = "bar"
Sequence. Similar.
t = {}
t[1] = 123
t["bar"] = "foo"
t[2] = "bar"
t[false] = 1
t[3] = 0
Sequence. We don't care about non-numeric keys.
Diving into the implementation
(if you really have to know)
But what happens in C implementation of Lua when we call # on a non-sequence?
Background: Tables in Lua are internally divided into array part and hash part. That's an optimization. Lua tries to avoid allocating memory often, so it pre allocates for the next power of two. That's another optimization.
When the last item in the array part is nil, the result of # is the length of the shortest valid sequence found by binsearching the array part for the first nil-followed key.
When the last item in the array part is not nil AND the hash part is empty, the result of # is the physical length of the array part.
When the last item in the array part is not nil AND the hash part is NOT empty, the result of # is the length of the shortest valid sequence found by binsearching the hash part for for the first nil-followed key (that is such positive integer i that t[i] ~= nil and t[i+1] == nil), assuming that the array part is full of non-nils(!).
So the result of # is almost always the (desired) length of the shortest valid sequence, unless the last element in the array part representing a non-sequence is non-nil. Then, the result is bigger than desired.
Why is that? It seems like yet another optimization (for power-of-two sized arrays). The complexity of # on such tables is O(1), while other variants are O(log(n)).
In Lua only specially formed tables are considered an array. They are not really an array such as what one might consider as an array in the C language. The items are still in a hash table. But the keys are numeric and contiguous from 1 to N. Lua arrays are unit offset, not zero offset.
The bottom line is that if you do not know if the table you have formed meets the Lua criteria for an array then you must count up the items in the table to know the length of the table. That is the only way. Here is a function to do it:
function table_count(T)
local count = 0
for _ in pairs(T) do count = count + 1 end
return count
end
If you populate a table with the "insert" function used in the manner of the following example, then you will be guaranteed of making an "array" table.
s={}
table.insert(s,[whatever you want to store])
table.insert could be in a loop or called from other places in your code. The point is, if you put items in your table in this way then it will be an array table and you can use the # operator to know how many items are in the table, otherwise you have to count the items.

Is it right to assign multiple variables like this a = b = c = d = 5?

a = b = c = d = 5
puts (a) >> 5
puts (b) >> 5
puts (b) >> 5
puts (b) >> 5
a= a+1
puts (a) >> 6
puts (b) >> 5
I found there is no problem with the assigning of values like this. My question is should one assign like the one given above or like this?
a , b, c, d = 5, 5, 5, 5
The thing to be aware of here is that your case only works OK because numbers are immutable in Ruby. You don't want to do this with strings, arrays, hashes or pretty much anything else other than numbers, because it would create multiple references to the same object, which is almost certainly not what you want:
a = b = c = d = "test"
b << "x"
=> "testx"
a
=> "testx"
Whereas the parallel form is safe with all types:
a,b,c,d = "test","test","test","test"
=> ["test", "test", "test", "test"]
b << "x"
=> "testx"
a
=> "test"
There's nothing wrong with assigning it that way (a = b = c = d = 5). I personally prefer it over multiple assignment if all the variables need to have the same value.
Here's another way:
a, b, c, d = [5] * 4
If it feels good, do it.
The language allows it, as you discovered, and it behaves as you'd expect. I'd suggest that the only question you should ask yourself regards expressiveness: is the code telling you what its purpose is?
Personally, I don't particularly like using this construct for much other than initialisation to default values, preferably zero. Ideally the variables so initialised would all have a similar purpose as well, counters, for example. But if I had more than a couple of similarly-purposed variables I might very well consider declaring them to be a form of duplicate, to be refactored out into, for example, a Hash.
These two initializations express different meaning. The a = b = c = d = 5 means "all my variables should be initialized to the same value, and this value is 5". The other one, a, b, c, d = 5, 5, 5, 5, means "I have a list of variables, and corresponding list of init values".
Is your logic such that all the variables should always be the same? Then the first one is better. If not, the second one might be better. Another question: is your list of 4 variables comprehensive? is it likely that you will add or remove another variable to this group? If so, I'd suggest yet another variant instead:
a = 5
b = 5
c = 5
d = 5
I once got bitten with that one. It may save you a few keystrokes today but come to bite you later. As #glenn mentioned, it creates multiple references to the same object.
Example: This applies to both ruby 1.8 and 1.9
> a = b = Array.new
=> []
> a.object_id == b.object_id
=> true
> a << 1
=> [1]
> b << 2
=> [1, 2]
I don't use ruby at all, so that might be an acceptable idiom, but a = b = c = d = 5 looks pretty ugly to me. a , b, c, d = 5, 5, 5, 5 looks much nicer, IMO.

Resources