Lua Nested Unpack Bug? - lua

Question:
I'm trying to unpack an array into an array, but it only works if it's the last item unpacked, if there is anything after it only the first element is unpacked. The following is a very basic example of what I'm trying to do. Is there a better way to do this, or is this a bug I'll have to cope with? I don't want to use table.insert as this seems to be much more readable adding within the definition of the table with something like unpack.
Code:
print ("Error 1")
local table1 = { {1,1}, {2,2}, {3,3} }
local table2 = { {0,0}, unpack (table1), {4,4} }
for n,item in ipairs (table2) do print (unpack(item)) end
print ("Good")
table1 = { {1,1}, {2,2}, {3,3} }
table2 = { {0,0}, unpack (table1) }
for n,item in ipairs (table2) do print (unpack(item)) end
print ("Error 2")
table1 = { {1,1}, {2,2}, {3,3} }
table2 = { {0,0}, unpack (table1), unpack (table1) }
for n,item in ipairs (table2) do print (unpack(item)) end
Output:
Error 1
0 0
1 1 -- {2,2} & {3,3} cut off.
4 4
Good
0 0
1 1 -- All elements unpacked.
2 2
3 3
Error 2
0 0
1 1 -- {2,2} & {3,3} cut off.
1 1 -- All elements unpacked.
2 2
3 3
Note:
I'm running version 5.1.

This is not a bug. A function call that returns multiple values is adjusted to the first value if the call is not the last one. The manual says that at http://www.lua.org/manual/5.1/manual.html#2.5

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.

Check for identical elements in a table in Lua?

How would you check a table for three identical elements (looking for three L's)?
table = {nil, nil, L, nil, L} -> false
table = {L, L, nil, nil, L} -> true
Really would appreciate some help!
EDIT: Ok I've got this, but it only outputs false even when there are three or more L's (and does so five times for every check?). Sorry if it seemed like I was trying to get the code for it, I'm genuinely trying to learn! :)
for k, v in pairs( threeL_table ) do
local count = 0
if k == 'L' then
count = count + 1
end
if count == 3 then
print('true')
else
print('false')
end
end
You were almost there. You need to test the values v against 'L', not the keys k. Also, I suppose you want to print the message only once after the scan is concluded; if so, put the if-statement outside of the for-loop. (In this case, you should define count outside of the for-loop, too, otherwise you would not see it once it has ended).
local count = 0
for k, v in pairs( threeL_table ) do
if v == 'L' then -- you need to check for the values not the keys
count = count + 1
end
end
if count == 3 then -- move this out of the for-loop
print('true')
else
print('false')
end
I will not give you any code as you did not show any own efforts to solve the problem.
How would you check a table for three identical elements? Well you count them.
Loop over the table and for every distinct value you create a new counter. You could use another table for that. Once one of those counters reaches 3 you know that you have three identical values.
Another way to solve this.
function detectDup(t,nDup)
table.sort(t)
local tabCount = {}
for _,e in ipairs(t) do
tabCount[e] = (tabCount[e] or 0) + 1
if tabCount[e] >= 3 then
print("The element '" .. e .. "' has more than 3 repetitions!")
return true
end
end
return false
end
print(detectDup({'L', 'L','A','B'},3))
print(detectDup({'L', 'L','A','B','L',},3))

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

Printing certain number of rows using awk. AND skipping certain rows

I have a simple question, which is almost too simple to find on this forum or on awk learning sites.
I have some awk code that matches a line beginning with a number, and prints the 6th column of that line:
/^[1-9]/ {
print $6
}
How do I tell it to print only the first 50 rows of the column from the match?
ADDITIONAL QUESTION
I tried used my own version of the answers below and I got it to print 50 lines. However, now I am trying to choose which 50 lines I print. I do this by skipping a line that starts with a number and contains the word 'residue'. Then I skip 5 lines that start with a number and contain a 'w'. This method is working as if I am only skipping the line with residue and prints from the first line starting with a number after that. Do you know why my 'w's are not being considered.
#!/usr/bin/awk -f
BEGIN {
line = 0;
skipW = 0;
}
# Ignore all lines beginning with a number until I find one I'm interested in.
/^[0-9]+ residue/ { next }
# Ignore the first five lines beginning with a number followed by a 'w'.
/^[0-9]+ w/ {
skipW += 1;
if (skipW <= 5) next
}
# For all other lines beginning with a number, perform the following. If we are
# "printing", increment the line count. When we've printed 50 lines turn off
# printing from that point on.
/^[0-9]+/ {
++line
if ((line > 0) && (line <= 50)) print $6
}
Use a match counter as part of your condition:
/^[1-9]/ && matched < 50 {
print $6
matched++
}
You can use a shortcut method also:
/^[1-9]/ { print $6; matched++ }
matched == 50 { exit }
But this may not always work on a pipline, if the producer command does not handle SIGPIPE gracefully.
awk '/^[1-9]/ { if (num_printed++ < 50) print $6 }'
This increments num_printed each time a match is found and prints out the first 50 such lines, regardless of where the lines are in the files in the input.
This reads through all the input. If an early exit is OK, then you can use:
awk '/^[1-9]/ { print $6; if (++num_printed == 50) exit }'
Note the switch from post-increment to pre-increment.

how to "page" through the data in a Lua table used as a dictionary?

How would I code a function to iterate through one "pages" worth of data? Sample code would be ideal...
So say we image the size of a page is 5 items. If we had a lua table with 18 items it would need to print out:
Page 1: 1 to 5
Page 2: 6 to 10
Page 3: 11 to 15
Page 4: 16 to 18
So assume the data is something like:
local data = {}
data["dog"] = {1,2,3}
data["cat"] = {1,2,3}
data["mouse"] = {1,2,3}
data["pig"] = {1,2,3}
.
.
.
How would one code the function that would do the equivalent of this:
function printPage (myTable, pageSize, pageNum)
-- find items in "myTable"
end
So in fact I'm not even sure if a Lua table used as a dictionary can even do this? There is no specific ordering is there in such a table, so how would you be sure the order would be the same when you come back to print page 2?
The next function allows you to go through a table in an order (albeit an unpredictable one). For example:
data = { dog = "Ralf", cat = "Tiddles", fish = "Joey", tortoise = "Fred" }
function printPage(t, size, start)
local i = 0
local nextKey, nextVal = start
while i < size and nextKey ~= nil do
nextKey, nextVal = next(t, nextKey)
print(nextKey .. " = " .. nextVal)
i = i + 1
end
return nextKey
end
local nextPage = printPage(data, 2) -- Print the first page
printPage(data, 2, nextPage) -- Print the second page
I know this isn't quite in the form you were after, but I'm sure it can be adapted quite easily.
The next function returns the key after the one provided in the table, along with its value. When the end of the table is reached, it returns nil. If you provide nil as the second parameter, it returns the first key and value in the table. It's also documented in Corona, although it appears to be identical.

Resources