Strange table error in Lua - lua

Okay, so I've got a strange problem with the following Lua code:
function quantizeNumber(i, step)
local d = i / step
d = round(d, 0)
return d*step
end
bar = {1, 2, 3, 4, 5}
local objects = {}
local foo = #bar * 3
for i=1, #foo do
objects[i] = bar[quantizeNumber(i, 3)]
end
print(#fontObjects)
After this code has been run, the length of objects should be 15, right? But no, it's 4. How is this working and what am I missing?
Thanks, Elliot Bonneville.

Yes it is 4.
From the Lua reference manual:
The length of a table t is defined to be any integer index n such that t[n] is not nil and t[n+1] is nil; moreover, if t[1] is nil, n can be zero. For a regular array, with non-nil values from 1 to a given n, its length is exactly that n, the index of its last value. If the array has "holes" (that is, nil values between other non-nil values), then #t can be any of the indices that directly precedes a nil value (that is, it may consider any such nil value as the end of the array).
Let's modify the code to see what is in the table:
local objects = {}
local foo = #bar * 3
for i=1, foo do
objects[i] = bar[quantizeNumber(i, 3)]
print("At " .. i .. " the value is " .. (objects[i] and objects[i] or "nil"))
end
print(objects)
print(#objects)
When you run this you see that objects[4] is 3 but objects[5] is nil. Here is the output:
$ lua quantize.lua
At 1 the value is nil
At 2 the value is 3
At 3 the value is 3
At 4 the value is 3
At 5 the value is nil
At 6 the value is nil
At 7 the value is nil
At 8 the value is nil
At 9 the value is nil
At 10 the value is nil
At 11 the value is nil
At 12 the value is nil
At 13 the value is nil
At 14 the value is nil
At 15 the value is nil
table: 0x1001065f0
4
It is true that you filled in 15 slots of the table. However the # operator on tables, as defined by the reference manual, does not care about this. It simply looks for an index where the value is not nil, and whose following index is nil.
In this case, the index that satisfies this condition is 4.
That is why the answer is 4. It's just the way Lua is.
The nil can be seen as representing the end of an array. It's kind of like in C how a zero byte in the middle of a character array is actually the end of a string and the "string" is only those characters before it.
If your intent was to produce the table 1,1,1,2,2,2,3,3,3,4,4,4,5,5,5 then you will need to rewrite your quantize function as follows:
function quantizeNumber(i, step)
return math.ceil(i / step)
end

The function quantizeNumber is wrong. The function you're looking for is math.fmod:
objects[i] = bar[math.fmod(i, 3)]

Related

save strings in lua table

Does someone know a solution to save the key and the values to an table? My idea does not work because the length of the table is 0 and it should be 3.
local newstr = "3 = Hello, 67 = Hi, 2 = Bye"
a = {}
for k,v in newstr:gmatch "(%d+)%s*=%s*(%a+)" do
--print(k,v)
a[k] = v
end
print(#a)
The output is correct.
run for k,v in pairs(a) do print(k,v) end to check the contents of your table.
The problem is the length operator which by default cannot be used to get the number of elements of any table but a sequence.
Please refer to the Lua manual: https://www.lua.org/manual/5.4/manual.html#3.4.7
When t is a sequence, #t returns its only border, which corresponds to
the intuitive notion of the length of the sequence. When t is not a
sequence, #t can return any of its borders. (The exact one depends on
details of the internal representation of the table, which in turn can
depend on how the table was populated and the memory addresses of its
non-numeric keys.)
Only use the length operator if you know t is a sequence. That's a Lua table with integer indexes 1,..n without any gap.
You don't have a sequence as you're using non-numeric keys only. That's why #a is 0
The only safe way to get the number of elements of any table is to count them.
local count = 0
for i,v in pairs(a) do
count = count + 1
end
You can put #Piglet' code in the metatable of a as method __len that is used for table key counting with length operator #.
local newstr = "3 = Hello, 67 = Hi, 2 = Bye"
local a = setmetatable({},{__len = function(tab)
local count = 0
for i, v in pairs(tab) do
count = count + 1
end
return count
end})
for k,v in newstr:gmatch "(%d+)%s*=%s*(%a+)" do
--print(k,v)
a[k] = v
end
print(#a) -- puts out: 3
The output of #a with method __len even is correct if the table holds only a sequence.
You can check this online in the Lua Sandbox...
...with copy and paste.
Like i do.

Lua Table Gap aviod

Why lua table (rehashes?) avoid gaps when I use different syntax?
inspect function
d = require "core/modules/inspect"
Case1: standart syntax 1st element is a gap
t = {1,2,3}
t[1] = nil
d(t)
__________
{ nil, 2, 3 }
Case2: with brackets syntax is no gaps
t = {
[1] = 1,
[2] = 2,
[3] = 3,
}
t[2] = nil
d(t)
__________
{ 1,
[3] = 3
}
Case3: dynamic array - no gaps
t = {}
t[1] = 1
t[2] = 2
t[3] = 3
t[2] = nil
d(t)
__________
{ 1,
[3] = 3
}
Case4: dynamic array when set nil in 1st element - is a gap
t = {}
t[1] = 1
t[2] = 2
t[3] = 3
t[1] = nil
d(t)
__________
{ nil, 2, 3 }
Case5: with brackets syntax set nil in 1st element is still no gaps
t = {
[1] = 1,
[2] = 2,
[3] = 3,
}
t[1] = nil
d(t)
__________
{
[2] = 2,
[3] = 3
}
Lua does not define behaviour for the length operator for non-sequential indexes, but the accepted answer to Why does Lua's length (#) operator return unexpected values? goes into what practically happens in the standard implementation of Lua 5.2. That said, that answer on its own doesn't completely explain the behaviour, so here's a case-by-case explanation, using Lua 5.3.5's standard implementation.
Note: I use the length operator to clearly show cases where holes are occuring. Regarding how this applies to the inspection function you've used, from what I can see of its behaviour it simply explicitly states any indexes outside of the range 1 <= index <= #table.
Case 1:
> t = {1,2,3}
> t[1] = nil
> print(#t)
3
The size of a Lua table's array part is based on a power of two - except when a table is constructed with pre-set values. The line t = {1,2,3} creates a table with an array part of size 3. When you perform t[1] = nil, the array part has no reason to re-size, so its size remains at 3. As the last item in the array part is non-nil, and the hash part is empty, the array size - 3 - is returned.
Case 2:
> t = {[1] = 1, [2] = 2, [3] = 3}
> t[2] = nil
> print(#t)
1
If you're defining table values within the table constructor, Lua will associate any key within square brackets with the hash part of the table. So, the array part of the table is actually empty. The implementation performs a binary search on the hash part of the array, and gets 1.
Case 3:
> t = {}
> t[1] = 1
> t[2] = 2
> t[3] = 3
> t[2] = nil
> print(#t)
1
When square brackets are used outside of the constructor, Lua will check numerical indexes to see if they should go into the array part or the hash part. In this case, each of the indexes will go into the array part, but because these values are defined outside of the constructor, the array will be sized on assignment based on powers of two. So, after the initial three assignments the array part will have a size of 4. The nil assignment doesn't trigger a re-size, so it stays at 4. Thus, when the length operator is applied, it sees that the final value in the array's space is nil, and so it binary searches for the index before the first nil value, which is 1.
Case 4:
> t = {}
> t[1] = 1
> t[2] = 2
> t[3] = 3
> t[1] = nil
> print(#t)
3
This case is exactly the same case Case 3, but the binary search sees that t[2] is non-nil and so doesn't consider the values at any index before 2. This results in the search continuing on the indexes after 2, which concludes that the length is 3.
Case 5:
> t = {[1] = 1, [2] = 2, [3] = 3}
> t[1] = nil
> print(#t)
0
This is like Case 2 in the sense that the table items are members of the hash part of the table. In this case, however, the search process results in 0. This is because before attempting the binary search, the function determines what range of integer indexes it should search over. The presence of a nil value at the first index means that the loop which determines the range doesn't run. For more information on how that search process works, you can see the function here. When I say the loop doesn't run, I am specifically referring to the while condition, !ttisnil(luaH_getint(t, j)).
Bonus case:
> t = {}
> t[1] = 1
> t[4] = 4
> print(#t)
1
> g = {}
> g[1] = 1
> g[3] = 3
> g[4] = 4
> print(#g)
4
In Case 3 I mentioned the fact that Lua decides whether to put a numerical index in the array part or the hash part. In the composition of the table t above, index 1 is in the array part and 4 in the hash part. As such, the length returned is 1. In the case of g, all values are placed into the array part. This is because when assigning values to indexes, Lua tries to re-size the array part in an optimal way. For a greater understanding of this re-sizing process, you can view the source here.

Inserting and removing table element in Lua

I don't understand why the following code produces error.
The code begins with the main() function at the bottom.
heads = {}
function push(t)
if (#t == 2) then
table.insert(heads, t)
end
end
function remove(id)
for i = 1, #heads do
if (heads[i][2] == id) then
table.remove(heads, i)
end
end
end
function main()
push({50, 1})
push({50, 2})
push({50, 3})
remove(2)
end
When I run the code, I get attempt to index a nil value (field '?') error.
I expect to push the subtable elements into the table and then remove only the second one. So the resulting elements can be {50, 1} and {50, 3}.
Why is my code not working and how to fix this?
Andrew got it right. Never try to remove a value inside a table when you iterate the table. This is a common issue in many languages. Usually, you would store the value first and then remove like so:
local e
for i = 1, #heads do
if (heads[i][2] == id) then
e = i
end
end
if e then table.remove(heads, e) end
However, this solution is slow. Simply use the ID as key of your table:
local heads = {}
heads[1] = 50 -- push
heads[2] = 50
heads[3] = 50
heads[2] = nil -- remove
No need for unnecessary function calls and iterations.
According to 5.1 manual table.remove "Removes from table the element at position, shifting down other elements to close the space, if necessary"
size of heads (#heads) is calculated once before loop execution, when i==2 you call table.remove, and so size of the table shrinks to 2, and on next iteration you try index heads[3][2], but heads[3] is nil, therefore "attempt to index a nil value" error message.
As Andrew mentioned, for i = 1, #heads do will go to the original length of the list; if you shorten heads during the loop, then the final iteration(s) will read heads[i] and find only nil.
A simple way to fix this is to move backwards through the list, since removing an element only affects indices after the index you have removed from:
for i = #heads, 1, -1 do
if heads[i][2] == id then
table.remove(heads, i)
end
end
Note that in any case, this is O(n*d) complexity and could be very slow if you are deleting many elements from the list. And, as others pointed out, there's a O(1) approach where you use a map from v[1] => v instead.
To avoid problems caused by removing fields while iterating over an array, I've used a while loop with an index variable, which is incremented at the end of each iteration, but decremented when an index is removed. So, for instance, to remove all elements with an even index:
local t = { 1, 2, 3, 4, 5 }
local i = 1
while t[i] do
if t[i] % 2 == 0 then
table.remove(t, i)
i = i - 1
end
i = i + 1
end
This method allows you to iterate over array indices in ascending order.
Addressing this iteration, in case of many items that are to be removed, I'd rather go for
local result = {}
for _, v in ipairs(myTab) do
if v == 'nice' then
table.insert(result, v)
end
end
myTab = result
as table.remove is slow when shifting many elements.

How to initialize table size in lua

What is the most efficient way to convert number to table? Or is it possible to make a table without loops?
local t = 10 -- given number
{1, 2, 3, 4, 5, 6, 7, 8, 9, 10} -- result
Update: the t variable is mutable number and I want to for each the value.
t = 3
function foreach(f, t)
for i, v in ipairs(t) do
f(v)
end
end
foreach(print, t)
1
2
3
I need a just the quickest way of new Array(n) in Lua. Or doesn't make any sense?
Maybe you don't know how to answer #Sebastian's question. Here are a few alternatives to get you thinking.
Since your table has only computed elements, you could omit the storage and just perform the calculation on every read access (index operation).
local function newArray(size)
local t = {}
setmetatable(t, {
__index = function (_, i)
return i >= 1 and i <= size and i or nil end})
return t
end
t10 = newArray(10)
for i = 0, 11 do -- ipairs won't work as expected with such a table
print(i, t10[i])
end
t10[2] = "stored values override __index"
print(t10[2])
Of course, you could also replace the table with just an identity function that returns the value, or even just an identity expression. But, maybe you have an unexpressed requirement for a table or you need ipairs to iterate over the sequence.
Speaking of iterators,
local function seq_itor(first, last)
local i = first - 1
return function ()
i = i + 1
if i <= last then return i end
end
end
for i in seq_itor(1, 10) do
print(i)
end
The simplest way to do that would be to define a function:
function newArray(size)
local t = {}
for i = 1, size do
t[i] = i
end
return t
end

Behavior of load() when chunk function returns nil

From the Lua 5.1 documentation for load():
Loads a chunk using function func to get its pieces. Each call to func must return a string that concatenates with previous results. A return of an empty string, nil, or no value signals the end of the chunk.
From my testing, this is not actually true. Or, rather, the documentation is at a minimum misleading.
Consider this example script:
function make_loader(return_at)
local x = 0
return function()
x = x + 1
if x == return_at then return 'return true' end
return nil
end
end
x = 0
repeat
x = x + 1
until not load(make_loader(x))()
print(x)
The output is the number of successive calls to the function returned by make_loader() that returned nil before load() gives up and returns a function returning nothing.
One would expect the output here to be "1" if the documentation is to be taken at face value. However, the output is "3". This implies that the argument to load() is called until it returns nil three times before load() gives up.
On the other hand, if the chunk function returns a string immediately and then nil on subsequent calls, it only takes one nil to stop loading:
function make_loader()
local x = 0
return {
fn=function()
x = x + 1
if x == 1 then return 'return true' end
return nil
end,
get_x=function() return x end
}
end
loader = make_loader()
load(loader.fn)
print(loader.get_x())
This prints "2" as I would expect.
So my question is: is the documentation wrong? Is this behavior desirable for some reason? Is this simply a bug in load()? (It seems to appear intentional, but I cannot find any documentation explaining why.)
This is a bug in 5.1. It has been corrected in 5.2, but we failed to incorporate the correction in 5.1.
I get slightly different results from yours, but they are still not quite what the documentation implies:
function make_loader(return_at)
local x = 0
return function()
x = x + 1
print("make_loader", return_at, x)
if x == return_at then return 'return true' end
return nil
end
end
for i = 1, 4 do
load(make_loader(i))
end
This returns the following results:
make_loader 1 1
make_loader 1 2
make_loader 2 1
make_loader 2 2
make_loader 2 3
make_loader 3 1
make_loader 3 2
make_loader 4 1
make_loader 4 2
For 1 it's called two times because the first one was return true and the second one nil. For 2 it's called three times because the first one was nil, then return true, and then nil again. For all other values it's called two times: it seems like the very first nil is ignored and the function is called at least once more.
If that's indeed the case, the documentation needs to reflect that. I looked at the source code, but didn't see anything that could explain why the first returned nil is ignored (I also tested with empty string and no value with the same result).

Resources