For a new index from two indexes in a for loop - lua

I was working on lua and looped over two tables and wanted to create a new table out of it, with no nil values in it. So this is basically a cross product. E.g:
{1,2,3} x {3,4,5} -> {1*3,1*4,1*5,2*3,2*4,2*5,3*3,3*4,3*5}
Of course this is not hard to do:
t = {1,2,3}
s = {3,4,5}
xs = {}
q = 1
for i,h in ipairs(t) do
for j,k in ipairs(s) do
xs[q] = h * k
q = q + 1
end
end
We keep a counter q and add 1 every iteration. And this works fine. However is it also possible without a counter? Can I fill up x so with just i and j such that there are no gaps in x?
t = {1,2,3}
s = {3,4,5}
xs = {}
for i,h in ipairs(t) do
for j,k in ipairs(s) do
q = f(i,j) -- <- I want to know if f is possible to write
xs[q] = h * k
end
end
I would say not, at least I was not able to find one myself easily.
EDIT: It is possible though if I am allowed to use the size of s.
s = {1,2,3}
t = {4,5,6}
xs = {}
for i,h in ipairs(s) do
for j,k in ipairs(t) do
q = i + (j - 1) * #t
xs[q] = h * k
end
end

You can use table.insert, there is no reason to specify the index in your case.
s = {1,2,3}
t = {4,5,6}
xs = {}
for i,h in ipairs(s) do
for j,k in ipairs(t) do
table.insert(xs, h * k)
end
end
for _, v in ipairs(xs) do
print(v)
end
Resource on insert:
https://www.lua.org/pil/19.2.html

Related

How to do recursive iterators in lua?

I can usually work out how to code the iterators I want in LUA.
But recursive iterators have me beat.
For example, here's a Python recursive iterator that returns all items in a nested list:
def items(x):
if isinstance(x,(list,tuple)):
for y in x:
for z in items(y): yield z
else:
yield x
for x in items([10,20,[30,[40,50],60],[70,80]]): print(x)
This prints
10
20
30
40
50
60
70
80
But I can't get it going in Lua. I think it is because I don't know how to carry around the state of the recursive traversal from one step in the iteration to the next.
Suggestions?
FP style
local function items(tbl, outer_iter)
local index = 0
local function iter()
index = index + 1
return tbl[index]
end
return
function ()
while iter do
local v = iter()
if v == nil then
iter, outer_iter = outer_iter
elseif type(v) == "table" then
iter = items(v, iter)
else
return v
end
end
end
end
Coroutine style
local function items(tbl)
return coroutine.wrap(
function()
for _, v in ipairs(tbl) do
if type(v) == "table" then
local iter = items(v)
local v = iter()
while v ~= nil do
coroutine.yield(v)
v = iter()
end
else
coroutine.yield(v)
end
end
end
)
end
Usage example:
for x in items{10,20,{30,{},{40,50},60},{70,80}} do
print(x)
end

String with Numbers to Table

How can i transform this following string:
string = "1,2,3,4"
into a table:
table = {1,2,3,4}
thanks for any help ;)
Let Lua do the hard work:
s="1,2,3,4"
t=load("return {"..s.."}")()
for k,v in ipairs(t) do print(k,v) end
Below is the code adapted from the Scribunto extension to MediaWiki. It allows to split strings on patterns that can be longer than one character.
-- Iterator factory
function string:gsplit (pattern, plain)
local s, l = 1, self:len()
return function ()
if s then
local e, n = self:find (pattern, s, plain)
local ret
if not e then
ret = self:sub (s)
s = nil
elseif n < e then
-- Empty separator!
ret = self:sub (s, e)
if e < l then
s = e + 1
else
s = nil
end
else
ret = e > s and self:sub (s, e - 1) or ''
s = n + 1
end
return ret
end
end, nil, nil
end
-- Split function that returns a table:
function string:split (pattern, plain)
local ret = {}
for m in self:gsplit (pattern, plain) do
ret [#ret + 1] = m
end
return ret
end
-- Test:
local str = '1,2, 3,4'
print ('table {' .. table.concat (str:split '%s*,%s*', '; ') .. '}')
You can use gmatch and the pattern (%d+) to create an iterator and then populate the table.
local input = "1,2,3,4"
local output = {}
for v in input:gmatch("(%d+)") do
table.insert(output, tonumber(v))
end
for _,v in pairs(output) do
print(v)
end
The pattern (%d+) will capture any number of digits(0-9).
This is a narrow solution, it does not handle blank entries such as
input = "1,2,,4"
output = {1,2,4}
It also does not care what the delimitator is, or if it is even consistent for each entry.
input = "1,2 3,4"
output = {1,2,3,4}
Reference:
Lua 5.3 Manual, Section 6.4 – String Manipulation: string.gmatch
FHUG: Understanding Lua Patterns

Get values of items inside a table

local sometable = {a = "ag", b = "fa"}
for k, v in ipairs(sometable) do
print(k, v)
end
The code above is my effort, so how do i print a, b in that table?!
You are using the wrong iterator. ipairs is for sequences. For hash-like tables, use pairs instead:
for k, v in pairs(sometable) do
ipairs only traversers the array part of a table. What you can do is simply writing
print(sometable.a, sometable.b)
or you can cycle through both the dictionary and array parts of the table by using
for key, value in pairs(sometable)
You could also define your own iterator to only cycle through the dictionary part of the table. In my mind it would look like
function cycle(dict)
local contentarray = {}
for k, v in pairs(dict) do
contentarray[#contentarray + 1] = {k, v}
end
local n = 0
return function()
n = n + 1
if not contentarray[n] then
return
else
while type(contentarray[n][1]) ~= "string" do
n = n + 1
end
return contentarray[n][1], contentarray[n][2]
end
end
end
But that would be higly inefficient.

One loop for iterating through multiple Lua tables

Is it possible to iterate through multiple Lua tables with the same loop?
For looping through indexed tables I can do something like this:
local t1 = {"a", "b", "c"}
local t2 = {"d", "e", "f"}
local num = #t1+#t2
for i=1, num, do
local j
local val
if i <= #t1 then
j = i
val = t1[j]
else
j = i-#t1
val = t2[j]
end
-- Do stuff
end
but how about key-value tables?
E.g. something like this:
local t1 = {a="a", b="b", c="c"}
local t2 = {d="d", e="e", f="f"}
for key, val in pairs(t1) or pairs(t2) do
print(key..": '"..val.."'")
end
should result in this:
a: 'a'
b: 'b'
c: 'c'
d: 'd'
e: 'e'
f: 'f'
function pairs(t, ...)
local i, a, k, v = 1, {...}
return
function()
repeat
k, v = next(t, k)
if k == nil then
i, t = i + 1, a[i]
end
until k ~= nil or not t
return k, v
end
end
local t1 = {a="a", b="b", c="c"}
local t2 = {d="d", e="e", f="f"}
for key, val in pairs(t1, t2) do
print(key..": '"..val.."'")
end
Note: this implementation does not respect __pairs metamethod.
For the given example, I think it is much more concise and clear to just wrap the loop in an outer loop that iterates the tables.
I am assuming the primary reason OP was looking for a solution other than two loops was to avoid having to write the inner logic twice. This is a good solution to that problem and only adds two lines of code:
local t1 = {a="a", b="b", c="c"}
local t2 = {d="d", e="e", f="f"}
for _, tbl in ipairs({ t1, t2 }) do
for key, val in pairs(tbl) do
print(key..": '"..val.."'")
end
end
While it's always nice to have an iterator like Egor's, a more efficient solution would simply be
local t1 = {a="a", b="b", c="c"}
local t2 = {d="d", e="e", f="f"}
for key, val in pairs(t1) do
print(key..": "..val)
end
for key, val in pairs(t2) do
print(key..": '"..val)
end
It's simple, concise, and easily understandable.

Operator overloading not working

While reading Programming in Lua, I tried this example given in the book for operator overloading
Set = {}
mt = {}
mt.__add = Set.union
--create a new set with the values of the given list
function Set.new (l)
local set = {}
setmetatable (set, mt)
for _, v in ipairs (l) do
set [v] = true
end
return set
end
function Set.union (a, b)
local result = Set.new {}
for k in pairs (a) do result [k] = true end
for k in pairs (b) do result [k] = true end
return result
end
function Set.intersection (a, b)
local result = Set.new {}
for k in pairs (a) do result [k] = b[k] end
return result
end
function Set.tostring (set)
local l = {}
for e in pairs (set) do
l[#l + 1] = e
end
return "{" .. table.concat (l, ", ") .. "}"
end
function Set.print (s)
print (Set.tostring (s))
end
s1 = Set.new {10, 20, 30, 50}
s2 = Set.new {30, 1}
Set.print (s1)
Set.print (s2)
s3 = s1 + s2
Set.print (s3)
But with the latest lua for windows I am getting the following error
lua: C:\meta.lua:47: attempt to perform arithmetic on global 's1' (a table value)
stack traceback:
C:\meta.lua:47: in main chunk
[C]: ?
{30, 10, 20, 50}
{1, 30}
You are making this assignment too early:
mt.__add = Set.union
because Set.union is not initialized yet.
Move this below Set.union and it will work.
For the same reason, if you assign mt.__mul, this should be below Set.intersection
You need to define mt as a suitable metatable:
mt = { __add = Set.union, __mul = Set.intersection, __tostring = Set.tostring }

Resources