Lua - unpack then pack an array - lua

If I unpack then pack an array:
arr = {1, 2, 3, 4, 5}
arr = table.pack(table.unpack(arr))
Will I guarantee that the resulting arr is the same as the initial arr?
In the documentation it states:
Note that the resulting table may not be a sequence.
What does this mean?

The documentation you cite is talking about nils as in
table.pack(1,nil,3).
Your table is a sequence and so table.unpack(arr) outputs no nils and table.pack(table.unpack(arr)) is a sequence.
However, table.pack(table.unpack(arr)) differs from the original arr because it contains a field n with value 5. This is the only difference.

Related

flatten an array of arbitrarily nested arrays of integers into a flat array of integers in ruby

how to write a code snippet Ruby that will flatten an array of arbitrarily nested arrays of integers into a flat array of integers. e.g. [[1,2,[3]],4] -> [1,2,3,4]. Please don't use any built-in flatten functions in either language.
Here's one solution without using the built-in flatten method. It involves recursion
def flattify(array)
array.each_with_object([]) do |element, flattened|
flattened.push *(element.is_a?(Array) ? flattify(element) : element)
end
end
I tested this out in irb.
flattify([[1,2,[3],4])
=> [1,2,3,4]
arr = [[1,2,[3]],4]
If, as in you example, arr contains only numbers, you could (as opposed to "should") do this:
eval "[#{arr.to_s.delete('[]')}]"
=> [1, 2, 3, 4]

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

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.

Sorting an array in Ruby (Special Case)

I have an array in Ruby which has values as follows
xs = %w(2.0.0.1
2.0.0.6
2.0.1.10
2.0.1.5
2.0.0.8)
and so on. I want to sort the array such that the final result should be something like this :
ys = %w(2.0.0.1
2.0.0.6
2.0.0.8
2.0.1.5
2.0.1.10)
I have tried using the array.sort function, but it places "2.0.1.10" before "2.0.1.5". I am not sure why that happens
Using a Schwartzian transform (Enumerable#sort_by), and taking advantage of the lexicographical order defined by an array of integers (Array#<=>):
sorted_ips = ips.sort_by { |ip| ip.split(".").map(&:to_i) }
Can you please explain a bit more elaborately
You cannot compare strings containing numbers: "2" > "1", yes, but "11" < "2" because strings are compared lexicographically, like words in a dictionary. Therefore, you must convert the ip into something than can be compared (array of integers): ip.split(".").map(&:to_i). For example "1.2.10.3" is converted to [1, 2, 10, 3]. Let's call this transformation f.
You could now use Enumerable#sort: ips.sort { |ip1, ip2| f(ip1) <=> f(ip2) }, but check always if the higher abstraction Enumerable#sort_by can be used instead. In this case: ips.sort_by { |ip| f(ip) }. You can read it as "take the ips and sort them by the order defined by the f mapping".
Split your data into chunks by splitting on '.'. There is no standard function to do it as such so you need to write a custom sort to perform this.
And the behaviour you said about 2.0.1.10 before 2.0.1.5 is expected because it is taking the data as strings and doing ASCII comparisons, leading to the result that you see.
arr1 = "2.0.0.1".split('.')
arr2 = "2.0.0.6".split('.')
Compare both arr1 and arr2 element by element, for all the data in your input.

Why does this array slice return an empty array instead of nil? [duplicate]

This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
Array slicing in Ruby: looking for explanation for illogical behaviour (taken from Rubykoans.com)
I've been playing around with array slicing in ruby but I don't understand the last 2 results below:
a = [1,2,3]
a[2,1] # output is [3]
a[3,1] # output is [] ...why??
a[4,1] # output is nil ...according to the docs this makes sense
Why would a[3,1] be an empty array while a[4,1] is nil?
If anything, I would expect a[3,1] to return nil as well. According to the ruby docs an array split should return nil if the start index is out of range. So why is it that a[3,1] is not returning nil?
Note: This is on ruby 1.9.2
You're asking for the end of the array, which is []. Look at it this way: the Array [1,2,3] can be considered to be constructed from cons cells as such: (1, (2, (3, ())), or 1:2:3:[]. The 3rd index (4th item) is then clearly [].
" Returns nil if the index (or starting index) are out of range."
a[3,1] is a special case according to the example in the same link.
more info can be seen here by the way: Array slicing in Ruby: looking for explanation for illogical behaviour (taken from Rubykoans.com)
It's easier to understand why if you imagine the slice on the left side of an assignment.
>> (b = a.clone)[2,1] = :a; p b
[1, 2, :a]
>> (b = a.clone)[2,0] = :b; p b
[1, 2, :b, 3]
>> (b = a.clone)[3,1] = :c; p b
[1, 2, 3, :c]
>> (b = a.clone)[3,0] = :d; p b
[1, 2, 3, :d]

Resources