What does a "for i, v" loop do? - lua

I understand, "for i, v" loops for tables, i is the index, and v is the value, but what does this script do? I do not think this has anything to do with tables, but the only type of for table loops I know in ROBLOX script is the first one I mentioned; "for i, v" loops, which loop through tables.
randomVariable = 1
for i = 1, randomVariable do
(random script)
end

This is a numeric loop statement.
for controlValue = startValue, endValue, stepValue do
-- for body
end
It goes from startValue until it reaches endValue, after running body code, controlValue is increased by stepValue. If controlValue is higher or equals to endValue the loop stops. If stepValue is not provided, it equals to 1.
It's equivalent to this code:
local controlValue = startValue
if not stepValue then stepValue = 1 end -- if no stepValue it equals to 1
while controlValue < endValue do
-- for body
controlValue = controlValue + stepValue
end

There are a few different ways to loop in Lua.
while variable < number do
repeat stuff until variable == number
for key, value in pairs do
for index, value in ipairs do
for i = 1, number do
i = 1 is the initial condition.
It usually begins at one, then loops through items in a table.
So you can think of it as an index in that regard.
where the randomVariable you mentioned would be #tab
however, you could set that initial condition to be larger, then count down.
for i = #tab, 1, -1 do
the third, optional argument is called "step size"
and it's the amount that initial condition is changed, after completing each loop. it defaults to 1, so it's not needed, most of the time.
so to step through all the even numbers in a table it would be
for i = 2, #tab, 2 do
Further reading: https://www.tutorialspoint.com/lua/lua_loops.htm

Related

Lua math.random explain

sorry for asking this question but I couldn't understand it
-- but i don't understand this code
ballDX = math.random(2) == 1 and 100 or -100
--here ballDY will give value between -50 to 50
ballDY = math.random(-50, 50)
I don't understand the structure what is (2) and why it's == 1
Thank you a lot
math.random(x) will randomly return an integer between 1 and x.
So math.random(2) will randomly return 1 or 2.
If it returns 1 (== 1), ballDX will be set to 100.
If it returns 2 (~= 1), ballDX will be set to -100.
A simple way to make a 50-50 chance.
That is a very common way of assigning variables in Lua based on conditionals. It’s the same you’d do, for example, in Python with “foo = a if x else b”:
The first function, math.random(2), returns either 1 or 2. So, if it returns 1 the part math.random(2) == 1 is true and so you assign 100 to the variable ballDX. Otherwise, assign -100 to it.
In lua
result = condition and first or second
basically means the same as
if condition and first ~= nil and first ~= false then
result = first
else
result = second
end
So in your case
if math.random(2) == 1 then
ballDX = 100
else
ballDX = -100
end
in other words, there is a 50/50 chance for ballDX to become 100 or -100
For a better understanding, a look at lua documentation helps a lot :
https://www.lua.org/pil/3.3.html
You can read:
The operator or returns its first argument if it is not false; otherwise, it returns its second argument:
So if the random number is 1 it will return the first argument (100) of the "or" otherwise it will return the second argument (-100).

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.

How can a Lua function return nil, even if the returned value is not nil inside the function?

I have created a function that (pseudo)randomly creates a table containing numbers. I then loop this function until at least correct result is found. As soon as I've confirmed that at least one such result exists, I stop the function and return the table.
When I create tables containing small values, there are no issues. However, once the random numbers grow to the range of hundreds, the function begins to return nil, even though the table is true the line before I return it.
local sort = table.sort
local random = math.random
local aMin, aMax = 8, 12
local bMin, bMax = 200, 2000
local function compare( a, b )
return a < b
end
local function getNumbers()
local valid = false
local numbers = {}
-- Generate a random length table, containing random number values.
for i = 1, random( aMin, aMax ) do
numbers[i] = random( bMin, bMax )
end
sort( numbers, compare )
-- See if a specific sequence of numbers exist in the table.
for i = 2, #numbers do
if numbers[i-1]+1 == numbers[i] or numbers[i-1] == numbers[i] then
-- Sequence found, so stop.
valid = true
break
end
end
for i = 1, #numbers-1 do
for j = i+1, #numbers do
if numbers[j] % numbers[i] == 0 and numbers[i] ~= 1 then
valid = true
break
end
end
end
if valid then
print( "Within function:", numbers )
return numbers
else
getNumbers()
end
end
local numbers = getNumbers()
print( "Outside function:", numbers )
This function, to my understanding, is supposed to loop infinitely until I find a valid sequence. The only way that the function can even end, according to my code, is if valid is true.
Sometimes, more often than not, with large numbers the function simply outputs a nil value to the outside of the function. What is going on here?
You're just doing getNumbers() to recurse instead of return getNumbers(). This means that if the recursion gets entered, the final returned value will be nil no matter what else happens.
In the else case of the if valid then, you are not returning anything. You only return anything in the valid case. In the else case, a recursive call may return something, but then you ignore that returned value. The print you see is corresponding to the return from the recursive call; it isn't making it out the original call.
You mean to return getNumbers().

Looping and adding chars to string in LUA

It's about Lua/Roblox. (Disclaimer: must be roblox compatible.) I have an array called "array1", and a number value "num" which is 0.
local array1 = {"1","2","3","etc."}
local num = 0
I do:
while 1 do
wait(1) -- just a little delay between loops
num = num + 1 -- every loop I'm increasing that "num" value with 1.
script.Parent.TextLabel.Text = array1[num] -- I'm setting Text to [num]th (in this case 1) of array1. (I get 1st, 2nd, 3rd, 4th etc. word every second)
end
And it works. Kinda. My problem is, it's setting it to:
"1" and then only "2", not "1" and then "12".
Here's some video of the problem: https://i.imgur.com/d63BoN5.gifv
And I don't want it that way. I want to it to be:
1, 12, 123.
Try this:
script.Parent.TextLabel.Text = script.Parent.TextLabel.Text .. array1[num]
This will concatenate the previous Text value with the next number.

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.

Resources