Get a certain value from a concatenated table - lua

Trying to allow a concatenated table to be referenced as such:
local group = table.concat(arguments, ",", 1)
where arguments = {"1,1,1"}
Currently, doing group[2] gives me the comma. How do I avoid that while still allowing for two-digit numbers?
(snippet of what I'm trying to use it for)
for i = 1, #group do
target:SetGroup(i, tonumber(group[i]))
end

Maybe you want something like
local i = 1
for v in string.gmatch(s, "(%w+),*") do
group[i] = v
i = i + 1
end
Revised version in response to comment, avoiding the table altogether:
local i = 1
for v in string.gmatch(s, "(%w+),*") do
target:SetGroup(i, tonumber(v))
i = i + 1
end

split function (you have to add it to code)
split = function(str, delim)
if not delim then
delim = " "
end
-- Eliminate bad cases...
if string.find(str, delim) == nil then
return { str }
end
local result = {}
local pat = "(.-)" .. delim .. "()"
local nb = 0
local lastPos
for part, pos in string.gfind(str, pat) do
nb = nb + 1
result[nb] = part
lastPos = pos
end
-- Handle the last field
result[nb + 1] = string.sub(str, lastPos)
return result
end
so
local arguments = {"1,1,1"};
local group = split(arguments[1], ",");
for i = 1, #group do
target:SetGroup(i, tonumber(group[i]))
end
also note that
local arguments = {"1,1,1"};
local group = split(arguments[1], ",");
local group_count = #group;
for i = 1, group_count do
target:SetGroup(i, tonumber(group[i]))
end
is faster code ;)

Related

Lua #Table returning 0, despite Table containing 3 elements (tables)? [duplicate]

Sounds like a "let me google it for you" question, but somehow I can't find an answer. The Lua # operator only counts entries with integer keys, and so does table.getn:
tbl = {}
tbl["test"] = 47
tbl[1] = 48
print(#tbl, table.getn(tbl)) -- prints "1 1"
count = 0
for _ in pairs(tbl) do count = count + 1 end
print(count) -- prints "2"
How do I get the number of all entries without counting them?
You already have the solution in the question -- the only way is to iterate the whole table with pairs(..).
function tablelength(T)
local count = 0
for _ in pairs(T) do count = count + 1 end
return count
end
Also, notice that the "#" operator's definition is a bit more complicated than that. Let me illustrate that by taking this table:
t = {1,2,3}
t[5] = 1
t[9] = 1
According to the manual, any of 3, 5 and 9 are valid results for #t. The only sane way to use it is with arrays of one contiguous part without nil values.
You can set up a meta-table to track the number of entries, this may be faster than iteration if this information is a needed frequently.
The easiest way that I know of to get the number of entries in a table is with '#'. #tableName gets the number of entries as long as they are numbered:
tbl={
[1]
[2]
[3]
[4]
[5]
}
print(#tbl)--prints the highest number in the table: 5
Sadly, if they are not numbered, it won't work.
There's one way, but it might be disappointing: use an additional variable (or one of the table's field) for storing the count, and increase it every time you make an insertion.
count = 0
tbl = {}
tbl["test"] = 47
count = count + 1
tbl[1] = 48
count = count + 1
print(count) -- prints "2"
There's no other way, the # operator will only work on array-like tables with consecutive keys.
function GetTableLng(tbl)
local getN = 0
for n in pairs(tbl) do
getN = getN + 1
end
return getN
end
You're right. There are no other way to get length of table
You could use penlight library. This has a function size which gives the actual size of the table.
It has implemented many of the function that we may need while programming and missing in Lua.
Here is the sample for using it.
> tablex = require "pl.tablex"
> a = {}
> a[2] = 2
> a[3] = 3
> a['blah'] = 24
> #a
0
> tablex.size(a)
3
local function CountedTable(x)
assert(type(x) == 'table', 'bad parameter #1: must be table')
local new_t = {}
local mt = {}
-- `all` will represent the number of both
local all = 0
for k, v in pairs(x) do
all = all + 1
end
mt.__newindex = function(t, k, v)
if v == nil then
if rawget(x, k) ~= nil then
all = all - 1
end
else
if rawget(x, k) == nil then
all = all + 1
end
end
rawset(x, k, v)
end
mt.__index = function(t, k)
if k == 'totalCount' then return all
else return rawget(x, k) end
end
return setmetatable(new_t, mt)
end
local bar = CountedTable { x = 23, y = 43, z = 334, [true] = true }
assert(bar.totalCount == 4)
assert(bar.x == 23)
bar.x = nil
assert(bar.totalCount == 3)
bar.x = nil
assert(bar.totalCount == 3)
bar.x = 24
bar.x = 25
assert(bar.x == 25)
assert(bar.totalCount == 4)
I stumbled upon this thread and want to post another option. I'm using Luad generated from a block controller, but it essentially works by checking values in the table, then incrementing which value is being checked by 1. Eventually, the table will run out, and the value at that index will be Nil.
So subtract 1 from the index that returned a nil, and that's the size of the table.
I have a global Variable for TableSize that is set to the result of this count.
function Check_Table_Size()
local Count = 1
local CurrentVal = (CueNames[tonumber(Count)])
local repeating = true
print(Count)
while repeating == true do
if CurrentVal ~= nil then
Count = Count + 1
CurrentVal = CueNames[tonumber(Count)]
else
repeating = false
TableSize = Count - 1
end
end
print(TableSize)
end
seems when the elements of the table is added by insert method, getn will return correctly. Otherwise, we have to count all elements
mytable = {}
element1 = {version = 1.1}
element2 = {version = 1.2}
table.insert(mytable, element1)
table.insert(mytable, element2)
print(table.getn(mytable))
It will print 2 correctly

problems with Lua match to find a pattern

I'm struggling with this problem:
Given 2 strings:
s1 = '/foo/:bar/oof/:rab'
s2 = '/foo/lua/oof/rocks'
I would like to produce the following information:
If they match (these two above should match, s2 follows a pattern described in s1).
A table holding the values of s2 in with the corresponding name in s1. In this case we would have: { bar = "lua", rab = "rocks" }
I think this algorithm solves it, but I can't figure how to implement it (probably with gmatch):
store the placeholders : indexes as KEYS of a table, and the respective VALUES being the name of these placeholders.
Example with s1:
local aux1 = { "6" = "bar", "15" = "rab" }
With the keys of aux1 fetched as indexes, extract the values of s2
into another table:
local aux2 = {"6" = "lua", "15" = "rocks"}
Finally merge them two into one table (this one is easy :P)
{ bar = "lua", rab = "rocks" }
Something like this maybe:
function comp(a,b)
local t = {}
local i, len_a = 0
for w in (a..'/'):gmatch('(.-)/') do
i = i + 1
if w:sub(1,1) == ':' then
t[ -i ] = w:sub(2)
else
t[ i ] = w
end
end
len_a = i
i = 0
local ans = {}
for w in (b..'/'):gmatch('(.-)/') do
i = i + 1
if t[ i ] and t[ i ] ~= w then
return {}
elseif t[ -i ] then
ans[ t[ -i ] ] = w
end
end
if len_a ~= i then return {} end
return ans
end
s1 = '/foo/:bar/oof/:rab'
s2 = '/foo/lua/oof/rocks'
for k,v in pairs(comp(s1,s2)) do print(k,v) end
Another solution could be:
s1 = '/foo/:bar/oof/:rab'
s2 = '/foo/lua/oof/rocks'
pattern = "/([^/]+)"
function getStrngTable(_strng,_pattern)
local t = {}
for val in string.gmatch(_strng,_pattern) do
table.insert(t,val)
end
return t
end
local r = {}
t1 = getStrngTable(s1,pattern)
t2 = getStrngTable(s2,pattern)
for k = 1,#t1 do
if (t1[k] == t2[k]) then
r[t1[k + 1]:match(":(.+)")] = t2[k + 1]
end
end
The Table r will have the required result
The solution below, which is some what cleaner, will also give the same result:
s1 = '/foo/:bar/oof/:rab'
s2 = '/foo/lua/oof/rocks'
pattern = "/:?([^/]+)"
function getStrng(_strng,_pattern)
local t = {}
for val in string.gmatch(_strng,_pattern) do
table.insert(t,val)
end
return t
end
local r = {}
t1 = getStrng(s1,pattern)
t2 = getStrng(s2,pattern)
for k = 1,#t1 do
if (t1[k] == t2[k]) then
r[t1[k + 1]] = t2[k + 1]
end
end

Lua table.concat

Is there a way to use the arg 2 value of table.concat to represent the current table index?
eg:
t = {}
t[1] = "a"
t[2] = "b"
t[3] = "c"
X = table.concat(t,"\n")
desired output of table concat (X):
"1 a\n2 b\n3 c\n"
Simple answer : no.
table.concat is something really basic, and really fast.
So you should do it in a loop anyhow.
If you want to avoid excessive string concatenation you can do:
function concatIndexed(tab,template)
template = template or '%d %s\n'
local tt = {}
for k,v in ipairs(tab) do
tt[#tt+1]=template:format(k,v)
end
return table.concat(tt)
end
X = concatIndexed(t) -- and optionally specify a certain per item format
Y = concatIndexed(t,'custom format %3d %s\n')
I don't think so: how would you tell it that the separator between keys and values is supposed to be a space, for example?
You can write a general mapping function to do what you'd like:
function map2(t, func)
local out = {}
for k, v in pairs(t) do
out[k] = func(k, v)
end
return out
end
function joinbyspace(k, v)
return k .. ' ' .. v
end
X = table.concat(map2(t, joinbyspace), "\n")
No. But there is a work around:
local n = 0
local function next_line_no()
n = n + 1
return n..' '
end
X = table.concat(t,'\0'):gsub('%f[%Z]',next_line_no):gsub('%z','\n')
function Util_Concat(tab, seperator)
if seperator == nil then return table.concat(tab) end
local buffer = {}
for i, v in ipairs(tab) do
buffer[#buffer + 1] = v
if i < #tab then
buffer[#buffer + 1] = seperator
end
end
return table.concat(buffer)
end
usage tab is where the table input is and seperator be both nil or string (if it nil it act like ordinary table.concat)
print(Util_Concat({"Hello", "World"}, "_"))
--Prints
--Hello_world

How do you reference a table with a key value that is numeric in Lua?

The output for the below script is:
AD[1] = [variable not found]
AD['2'] = bar
How can I modify the function getfield to return a value for v for both cases?
function getfield (f)
local v = _G
for w in string.gfind(f, "[%w_]+") do
v = v[w]
end
return v
end
AD = {[1] = 'foo', ['2'] = 'bar'}
data = {"AD[1]","AD['2']"}
for i,line in ipairs(data) do
s = getfield(line)
if s then
print(line .. " = " .. s)
else
print(line .. " = [variable not found]")
end
end
UPDATE:
I'm 90% sure, this is going to work for me:
function getfield (f)
local v = _G
for w in string.gfind(f, "['%w_]+") do
if (string.find(w,"['%a_]")==nil) then
w = loadstring('return '..w)()
else
w = string.gsub(w, "'", "")
end
v=v[w]
end
return v
end
This happens to work
function getfield (f)
local v = _G
for w in string.gfind(f, "['%w_]+") do
local x = loadstring('return '..w)()
print(w,x)
v = v[x] or v[w]
end
return v
end
AD = {[1] = 'foo', ['2'] = 'bar'}
data = {"AD[1]","AD['2']"}
for i,line in ipairs(data) do
s = getfield(line)
if s then
print(line .. " = " .. s)
else
print(line .. " = [variable not found]")
end
end
but it's pretty fragile.
Note that I added ' to the pattern.
The difficulty is that sometimes w is a string representing a name (key), and sometimes it's a string representing a number. In the second case it needs to be converted from string to number. But you need the context or some syntax to decide.
Here's the kind of fragility I mean:
> data = {"math[pi]","AD['2']"}
>
> for i,line in ipairs(data) do
>> s = getfield(line)
>> if s then
>> print(line .. " = " .. s)
>> else
>> print(line .. " = [variable not found]")
>> end
>> end
math table: 0x10ee05100
pi nil
math[pi] = 3.1415926535898
AD table: 0x10ee19ee0
'2' 2
AD['2'] = bar
> pi = 3
> math[3] = 42
> data = {"math[pi]","AD['2']"}>
> for i,line in ipairs(data) do
>> s = getfield(line)
>> if s then
>> print(line .. " = " .. s)
>> else
>> print(line .. " = [variable not found]")
>> end
>> end
math table: 0x10ee05100
pi 3
math[pi] = 42
AD table: 0x10ee19ee0
'2' 2
AD['2'] = bar
math[pi] is unchanged, but getfield interprets pi in the global context and gets 3 so the wrong field of math is returned.
You'll get the strings '1' and "'2'". You have to evaluate it to turn it into whatever object it is:
v = v[loadstring('return ' .. w)()]
Don't do this if the string came from an untrusted source though (like a user input or something) because they could execute arbitrary code.

How to get number of entries in a Lua table?

Sounds like a "let me google it for you" question, but somehow I can't find an answer. The Lua # operator only counts entries with integer keys, and so does table.getn:
tbl = {}
tbl["test"] = 47
tbl[1] = 48
print(#tbl, table.getn(tbl)) -- prints "1 1"
count = 0
for _ in pairs(tbl) do count = count + 1 end
print(count) -- prints "2"
How do I get the number of all entries without counting them?
You already have the solution in the question -- the only way is to iterate the whole table with pairs(..).
function tablelength(T)
local count = 0
for _ in pairs(T) do count = count + 1 end
return count
end
Also, notice that the "#" operator's definition is a bit more complicated than that. Let me illustrate that by taking this table:
t = {1,2,3}
t[5] = 1
t[9] = 1
According to the manual, any of 3, 5 and 9 are valid results for #t. The only sane way to use it is with arrays of one contiguous part without nil values.
You can set up a meta-table to track the number of entries, this may be faster than iteration if this information is a needed frequently.
The easiest way that I know of to get the number of entries in a table is with '#'. #tableName gets the number of entries as long as they are numbered:
tbl={
[1]
[2]
[3]
[4]
[5]
}
print(#tbl)--prints the highest number in the table: 5
Sadly, if they are not numbered, it won't work.
There's one way, but it might be disappointing: use an additional variable (or one of the table's field) for storing the count, and increase it every time you make an insertion.
count = 0
tbl = {}
tbl["test"] = 47
count = count + 1
tbl[1] = 48
count = count + 1
print(count) -- prints "2"
There's no other way, the # operator will only work on array-like tables with consecutive keys.
function GetTableLng(tbl)
local getN = 0
for n in pairs(tbl) do
getN = getN + 1
end
return getN
end
You're right. There are no other way to get length of table
You could use penlight library. This has a function size which gives the actual size of the table.
It has implemented many of the function that we may need while programming and missing in Lua.
Here is the sample for using it.
> tablex = require "pl.tablex"
> a = {}
> a[2] = 2
> a[3] = 3
> a['blah'] = 24
> #a
0
> tablex.size(a)
3
local function CountedTable(x)
assert(type(x) == 'table', 'bad parameter #1: must be table')
local new_t = {}
local mt = {}
-- `all` will represent the number of both
local all = 0
for k, v in pairs(x) do
all = all + 1
end
mt.__newindex = function(t, k, v)
if v == nil then
if rawget(x, k) ~= nil then
all = all - 1
end
else
if rawget(x, k) == nil then
all = all + 1
end
end
rawset(x, k, v)
end
mt.__index = function(t, k)
if k == 'totalCount' then return all
else return rawget(x, k) end
end
return setmetatable(new_t, mt)
end
local bar = CountedTable { x = 23, y = 43, z = 334, [true] = true }
assert(bar.totalCount == 4)
assert(bar.x == 23)
bar.x = nil
assert(bar.totalCount == 3)
bar.x = nil
assert(bar.totalCount == 3)
bar.x = 24
bar.x = 25
assert(bar.x == 25)
assert(bar.totalCount == 4)
I stumbled upon this thread and want to post another option. I'm using Luad generated from a block controller, but it essentially works by checking values in the table, then incrementing which value is being checked by 1. Eventually, the table will run out, and the value at that index will be Nil.
So subtract 1 from the index that returned a nil, and that's the size of the table.
I have a global Variable for TableSize that is set to the result of this count.
function Check_Table_Size()
local Count = 1
local CurrentVal = (CueNames[tonumber(Count)])
local repeating = true
print(Count)
while repeating == true do
if CurrentVal ~= nil then
Count = Count + 1
CurrentVal = CueNames[tonumber(Count)]
else
repeating = false
TableSize = Count - 1
end
end
print(TableSize)
end
seems when the elements of the table is added by insert method, getn will return correctly. Otherwise, we have to count all elements
mytable = {}
element1 = {version = 1.1}
element2 = {version = 1.2}
table.insert(mytable, element1)
table.insert(mytable, element2)
print(table.getn(mytable))
It will print 2 correctly

Resources