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

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().

Related

Generating all combinations from a table in Lua

I'm trying to iterate through a table with a variable amount of elements and get all possible combinations, only using every element one time. I've landed on the solution below.
arr = {"a","b","c","d","e","f"}
function tablelen(table)
local count = 0
for _ in pairs(table) do
count = count + 1
end
return count
end
function spellsub(table,start,offset)
local str = table[start]
for i = start+offset, (tablelen(table)+1)-(start+offset) do
str = str..","..table[i+1]
end
return str
end
print(spellsub(arr,1,2)) -- Outputs: "a,d,e" correctly
print(spellsub(arr,2,2)) -- Outputs: "b" supposed to be "b,e,f"
I'm still missing some further functions, but I'm getting stuck with my current code. What is it that I'm missing? It prints correctly the first time but not the second?
A solution with a coroutine iterator called recursively:
local wrap, yield = coroutine.wrap, coroutine.yield
-- This function clones the array t and appends the item new to it.
local function append (t, new)
local clone = {}
for _, item in ipairs (t) do
clone [#clone + 1] = item
end
clone [#clone + 1] = new
return clone
end
--[[
Yields combinations of non-repeating items of tbl.
tbl is the source of items,
sub is a combination of items that all yielded combination ought to contain,
min it the minimum key of items that can be added to yielded combinations.
--]]
local function unique_combinations (tbl, sub, min)
sub = sub or {}
min = min or 1
return wrap (function ()
if #sub > 0 then
yield (sub) -- yield short combination.
end
if #sub < #tbl then
for i = min, #tbl do -- iterate over longer combinations.
for combo in unique_combinations (tbl, append (sub, tbl [i]), i + 1) do
yield (combo)
end
end
end
end)
end
for combo in unique_combinations {'a', 'b', 'c', 'd', 'e', 'f'} do
print (table.concat (combo, ', '))
end
For a tables with consecutive integer keys starting at 1 like yours you can simply use the length operator #. Your tablelen function is superfluous.
Using table as a local variable name shadows Lua's table library. I suggest you use tbl or some other name that does not prevent you from using table's methods.
The issue with your code can be solved by printing some values for debugging:
local arr = {"a","b","c","d","e","f"}
function spellsub(tbl,start,offset)
local str = tbl[start]
print("first str:", str)
print(string.format("loop from %d to %d", start+offset, #tbl+1-(start+offset)))
for i = start+offset, (#tbl+1)-(start+offset) do
print(string.format("tbl[%d]: %s", i+1, tbl[i+1]))
str = str..","..tbl[i+1]
end
return str
end
print(spellsub(arr,1,2)) -- Outputs: "a,d,e" correctly
print(spellsub(arr,2,2)) -- Outputs: "b" supposed to be "b,e,f"
prints:
first str: a
loop from 3 to 4
tbl[4]: d
tbl[5]: e
a,d,e
first str: b
loop from 4 to 3
b
As you see your second loop does not ran as the start value is already greater than the limit value. Hence you only print the first value b
I don't understand how your code is related to what you want to achieve so I'll leave it up to you to fix it.

Computercraft function that returns an array, use first element for boolean

Edited for more details:
I'm trying to have a turtle that is sitting in front of a sapling wait for it to grow before cutting it down. It compares the log to the item in front until it matches. The system I'm currently using works, but I was hoping there was a slightly more minimal way to write it.
checkTarget = {
forward = function(tgt)
check = {turtle.inspect()} --creates table with first as boolean, second as information table
local rtn = {false, check[2]}
if type(tgt) == "table" then
for k, v in pairs(tgt) do
if check[2].name == v then
rtn = {true, v}
break
end
end
elseif tgt == nil then
return check[1]
elseif check[2].name == tgt then
rtn[1] = true
end
return rtn
end,--continued
This takes an argument, either a string or an array of strings, to compare against. When it checks the block in front it saves the detailed information to the second element in rtn and the first to a default of false. If the string matches the checked block's name, then it changes rtn[1] to true and returns all of it, which is the table at the bottom when doing checkTarget.forward("minecraft:log").
My question was, I am currently making a disposable variable to store the array that is returned from checkTarget, and then calling the variable's first element to get if it's true or not. I was hoping there was a way to include it in the if statement without the disposable variable (tempV)
repeat
local tempV = fox.checkTarget.forward("minecraft:log")
if tempV[1] then
cut()
fox.goTo({x = 0, y = 0, z = 0})
fox.face(0)
end
tempV = fox.checkTarget.forward("minecraft:log")
until not run
{
false,
{
state = {
stage = 0,
type = "birch",
},
name = "minecraft:sapling",
metadata = 2
}
}
Instead of
local tempV = fox.checkTarget.forward("minecraft:log")
if tempV[1] then
end
You can do
if fox.checkTarget.forward("minecraft:log")[1] then
end
and then calling the variable's first element to get if it's true or
not.
With tempV[1] you're not calling the first element, you're indexing it.
To call something you have to use the call operator () which doesn't make sense as a boolean is not callable.

Is the following Lua iterator stateless?

I'm confused with the concepts of stateless iterators. As an exercise I write an iterator to print all non-empty substrings of a given string. The code is as follows.
local function iter(state, i)
local str = state.str
if type(str) ~= "string" or str == "" then return nil end
if state.ending > #str then return nil end
local start = state.start
local ending = state.ending
if start == ending then
state.ending = ending + 1
state.start = 1
else
state.start = start + 1
end
return string.sub(str, start, ending)
end
function allSubstrings(str)
return iter, { str = str, start = 1, ending = 1 }, nil
end
for substr in allSubstrings("abcd123") do
print(substr)
end
I use a table { str = str, start = 1, ending = 1 } as the so-called invariant state, but I have to change the fields in this table in the iter local function. So is this iterator stateless or with complex states? If it's not stateless, is there a way to implement this functionality with a stateless iterator?
Thank you.
The PIL-chapter about stateless iterators states:
As the name implies, a stateless iterator is an iterator that does not keep any state by itself. Therefore, we may use the same stateless iterator in multiple loops, avoiding the cost of creating new closures.
In code that means that both for loops in:
f, s, var = pairs( t )
for k,v in f, s, var do print( k, v ) end
for k,v in f, s, var do print( k, v ) end
should produce the same output. This only works if neither the invariant state s nor any upvalues of the iterator function f change during the iteration, or else the second for loop would have different starting conditions than the first loop.
So, no, your iterator is not a stateless iterator because you change the invariant state during iteration.
There is a way to make your iterator stateless (and the popular Lua library luafun uses this technique extensively): keep all mutable state in the loop control variable var (even if you need to allocate a fresh table in each allocation step):
local function iter( str, var )
if type( str ) ~= "string" or str == "" then return nil end
if var[ 2 ] > #str then return nil end
local start, ending = var[ 1 ], var[ 2 ]
if start == ending then
return { 1, ending+1 }, string.sub( str, start, ending )
else
return { start+1, ending }, string.sub( str, start, ending )
end
end
function allSubstrings2( str )
return iter, str, { 1, 1 }
end
for _,substr in allSubstrings2( "abcd123" ) do
print( substr )
end
Drawbacks are that the first iteration variable var (the loop control variable) has no useful meaning for the user of the iterator, and since you have to allocate a table for each iteration step, "avoiding the cost of creating new closures" for another loop doesn't matter much.
luafun does it anyway, because it does not have the ability to recreate an iterator tuple (it is passed via function arguments from outside code), and for some algorithms you absolutely need to run the same iteration multiple times.
An alternative to this approach would be to concentrate all mutable state in the "invariant state" s (all upvalues to f must be immutable), and provide a way to copy/clone this state for later iterations:
f, s, var = allSubstrings("abcd123")
s2 = clonestate( s )
for str in f, s, var do print( str ) end
for str in f, s2, var do print( str ) end
This is still not a stateless iterator, but it is more memory-efficient than the stateless iterator with heap-allocated loop control variable, and it allows you to restart an iteration.
This is not a stateless iterator, and is indeed an iterator with complex state.
In stateless iterators there is only one control variable, and it should be treated as a pure value throughout the iterator.
You could consider using closures to implement this. Not quite stateless, but does use upvalues over table lookups, which should be more efficient.
local function allSubstrings (str)
if type(str) ~= "string" or str == "" then
return function () end -- NOP out on first iteration
end
local length = #str
local start, ending = 1, 1
return function ()
if ending > length then return nil end
local st, ed = start, ending
if start == ending then
ending = ending + 1
start = 1
else
start = start + 1
end
return string.sub(str, st, ed)
end
end
for substr in allSubstrings("abcd123") do
print(substr)
end
PIL book calls that 'Iterators with Complex State'
http://www.lua.org/pil/7.4.html

How to put floating points in LUA [duplicate]

I'd like to format a number to look like 1,234 or 1,234,432 or 123,456,789, you get the idea. I tried doing this as follows:
function reformatint(i)
local length = string.len(i)
for v = 1, math.floor(length/3) do
for k = 1, 3 do
newint = string.sub(mystring, -k*v)
end
newint = ','..newint
end
return newint
end
As you can see, a failed attempt, my problem is that I can't figure out what the error is because the program I am running this in refuses to report an error back to me.
Here's a function that takes negative numbers, and fractional parts into account:
function format_int(number)
local i, j, minus, int, fraction = tostring(number):find('([-]?)(%d+)([.]?%d*)')
-- reverse the int-string and append a comma to all blocks of 3 digits
int = int:reverse():gsub("(%d%d%d)", "%1,")
-- reverse the int-string back remove an optional comma and put the
-- optional minus and fractional part back
return minus .. int:reverse():gsub("^,", "") .. fraction
end
assert(format_int(1234) == '1,234')
assert(format_int(1234567) == '1,234,567')
assert(format_int(123456789) == '123,456,789')
assert(format_int(123456789.1234) == '123,456,789.1234')
assert(format_int(-123456789.) == '-123,456,789')
assert(format_int(-123456789.1234) == '-123,456,789.1234')
assert(format_int('-123456789.1234') == '-123,456,789.1234')
print('All tests passed!')
Well, let's take this from the top down. First of all, it's failing because you've got a reference error:
...
for k = 1, 3 do
newint = string.sub(mystring, -k*v) -- What is 'mystring'?
end
...
Most likely you want i to be there, not mystring.
Second, while replacing mystring with i will fix the errors, it still won't work correctly.
> =reformatint(100)
,100
> =reformatint(1)
,000
That's obviously not right. It seems like what you're trying to do is go through the string, and build up the new string with the commas added. But there are a couple of problems...
function reformatint(i)
local length = string.len(i)
for v = 1, math.floor(length/3) do
for k = 1, 3 do -- What is this inner loop for?
newint = string.sub(mystring, -k*v) -- This chops off the end of
-- your string only
end
newint = ','..newint -- This will make your result have a ',' at
-- the beginning, no matter what
end
return newint
end
With some rework, you can get a function that work.
function reformatint(integer)
for i = 1, math.floor((string.len(integer)-1) / 3) do
integer = string.sub(integer, 1, -3*i-i) ..
',' ..
string.sub(integer, -3*i-i+1)
end
return integer
end
The function above seems to work correctly. However, it's fairly convoluted... Might want to make it more readable.
As a side note, a quick google search finds a function that has already been made for this:
function comma_value(amount)
local formatted = amount
while true do
formatted, k = string.gsub(formatted, "^(-?%d+)(%d%d%d)", '%1,%2')
if (k==0) then
break
end
end
return formatted
end
You can do without loops:
function numWithCommas(n)
return tostring(math.floor(n)):reverse():gsub("(%d%d%d)","%1,")
:gsub(",(%-?)$","%1"):reverse()
end
assert(numWithCommas(100000) == "100,000")
assert(numWithCommas(100) == "100")
assert(numWithCommas(-100000) == "-100,000")
assert(numWithCommas(10000000) == "10,000,000")
assert(numWithCommas(10000000.00) == "10,000,000")
The second gsub is needed to avoid -,100 being generated.
I remember discussing about this in the LÖVE forums ... let me look for it...
Found it!
This will work with positive integers:
function reformatInt(i)
return tostring(i):reverse():gsub("%d%d%d", "%1,"):reverse():gsub("^,", "")
end
On the link above you may read details about implementation.

Lua Array shuffle not working

I was working on a script to randomize the data inside of my array but I get and error
that says
unexpected symbol near "#"
When I go to that line, and I remove the "#" I get
attempt to perform arithmetic on local `n' (a table value)
Here is my shuffle function
function shuffle(array)
local array = array
local n = #array
local j
local random = math.random
for i=n-1, 1, -1 do
j = random(i)
array[j],array[i] = array[i],array[j]
end
return array
end
and here is what I am trying to randomize
shuffle(new_players)
for name,character in pairs(new_players) do
if (character.inside == true and character.death == 0) then
local player = getPlayerByName(name, map_copy)
if (player ~= nil) then
addState(player)
break
end
end
end
Here is my array
new_players= { }
new_players[charName] = { death = 0, inside= true }
Any help? If i am doing something completely wrong?
1) Try change charName from string to a number.
2) For shuffle you can use this code:
function swap(array, index1, index2)
array[index1], array[index2] = array[index2], array[index1]
end
function shuffle(array)
local counter = #array
while counter > 1 do
local index = math.random(counter)
swap(array, index, counter)
counter = counter - 1
end
end
If your Lua version is < 5.1 then there is no # operator. Use table.getn instead:
local n = table.getn(array);
(Update) Note that your function, while it does shuffle the items around, it does not really shuffle all elements. Also since you reduce the range with each iteration, you will almost certainly swap the first 10% of your array around multiple times. Now swapping them multiple times is not bad by itself, but that you are, by comparison, almost never swapping the other elements is.
So one option to solve this would be to always use the same range for your random variable. And I would go even further and select two random indexes to swap:
function shuffle(array)
local n, random, j = table.getn(array), math.random
for i=1, n do
j,k = random(n), random(n)
array[j],array[k] = array[k],array[j]
end
return array
end
The other option would be to select random elements from the source array and put them into a new output array:
local rnd,trem,getn,ins = math.random,table.remove,table.getn,table.insert;
function shuffle(a)
local r = {};
while getn(a) > 0 do
ins(r, trem(a, rnd(getn(a))));
end
return r;
end

Resources