So I am trying to learn about metatables in lua, so i decided to follow some tutorials. I was trying out the __add part of metatables. But for some reason i kept on getting an error (attempt to perform arithmetic on field (nil)
aTable = {}
--Assign the values for the normal table
for x = 1, 10 do
aTable[x] = x
end
-- metatable
mt = {__add = function(table1, table2)
sumTable = {}
for i = 0, #table1 do
sumTable[i] = table1[i] + table2[i]
end
return sumTable
end}
setmetatable(aTable, mt)
newTable = {}
newTable = aTable + aTable
for x = 1, #newTable do
print(newTable[x])
end
At this point i am confused.Help would be appreciated
In the __add-function it should be:
for i = 1, #table1 do
since you didn't set table[0] initially, but started at index 1 (which is indeed recommended for lua-pseudoarrays, many operations rely on it)
#Ctx is correct that the problem is that differing indices in the array initialization and adding functions. But the best way to fix it is to modify your __add function to handle 'holes' in the arrays passed, by checking for nil entries in them.
for i = 0, #table1 do
if (table1[i] and table2[i]) then
sumTable[i] = table1[i] + table2[i]
end
end
Another thing that's missing: You don't set the same metatable on the result, which means that while things like aTable+aTable, aTable+aTable+aTable etc. will work, aTable+aTable+(aTable+aTable) will fail.
Corrected and cleaned version:
-- metatable
mt = {
__add = function( table1, table2 )
sumTable = {}
for i = 1, #table1 do
sumTable[i] = table1[i] + table2[i]
end
return setmetatable( sumTable, mt )
end,
}
aTable = setmetatable( {}, mt )
--Assign the values for the normal table
for x = 1, 10 do aTable[x] = x end
newTable = aTable + aTable
for x = 1, #newTable do print( newTable[x] ) end
-- and a test for what would have failed:
yetAnotherTable = newTable + newTable
for x = 1, #yetAnotherTable do print( yetAnotherTable[x] ) end
Related
So i have 2 tables
local table1 = {1,2,3,4,5,6,7,8,9}
local table2 = {2,4,6,8}
I want remove the number in table 2 from table 1, to then use table one with the numbers removed in more code. How would i go about doing this?
When you read the data into the table, set the value of the index of whatever you are reading in as the key in the table. This avoids collisions and allows easy comparisons against another table.
local table1 = {}
local table2 = {}
-- read in your values as keys into the two tables
-- just an example I have no idea how you are populating the tables but hope it helps
table1 = {['input1'] = 0, ['input6'] = 0, ['input3'] = 0}
table2 = {['input1'] = 0, ['input3'] = 0}
newTable = {}
function tableHasKey(table, key)
return table[key] ~= nil
end
for key, _ in pairs(table1) do
if not tableHasKey(table2, key) then
table.insert(newTable, key)
end
end
for _, value in pairs(newTable) do
print(value)
end
The result is 'input6' when I run this. Which means all values not in table2 that are in table1 are now in newTable. If the values are unique between tables it's easier to compare keys than values. The final result is an indexed table where the result is stored in the value of the hash object.
#! /usr/bin/env lua
local table1 = {1,2,3,4,5,6,7,8,9}
local table2 = {2,4,6,8}
for number = 1, #table1 do
for delete = 1, #table2 do
if table1[number] == table2[delete] then
for i = number, #table1 -1 do
table1[i] = table1[i +1]
end -- shuffle every entry in table down
table1 [#table1] = nil -- erase last entry
end -- number == delete
end -- loop through table2
end -- loop through table1
for i = 1, #table1 do print( table1[i] ) end
1
3
5
7
9
The other answers listed here seem correct, but they seem a little too aggressive on memory or time complexity. Here's my take on a filter function optimized for lists of numbers.
-- t1 : table, the original set of values
-- t2 : table, the set of values to remove from t1
-- returns : table, a subset of elements from t1 not found in t2
local function filter(t1, t2)
-- Assumptions :
-- 1) t1 and t2 are arrays, not dictionaries
-- 2) t1 and t2 do not have mixed indices or mixed values
-- 3) t1 and t2 are sorted
assert(type(t1) == "table", "t1 expected to be a table")
assert(type(t2) == "table", "t2 expected to be a table")
assert(type(next(t1)) == "number" or type(next(t1)) == "nil", "t1 expected to be an array")
assert(type(next(t2)) == "number" or type(next(t2)) == "nil", "t2 expected to be an array")
-- Early Outs :
if #t1 == 0 then
return {}
elseif #t2 == 0 then
return t1
end
-- step through each list and compare each index as you go
local filteredT = {}
local i = 1
local j = 1
local sizeT1 = #t1
local sizeT2 = #t2
while (i <= sizeT1) and (j <= sizeT2) do
if t1[i] == t2[j] then
-- found a match, exclude from output
i = i + 1
j = j + 1
elseif t1[i] < t2[j] then
-- no match, add elements from t1
table.insert(filteredT, t1[i])
i = i + 1
else -- t1[i] > t2[j]
-- no match, ignore elements from t2
j = j + 1
end
end
-- we've made it to the end of one of the lists, add the rest of t1
for i = i, sizeT1, 1 do
table.insert(filteredT, t1[i])
end
return filteredT
end
This solution doesn't have unnecessary loop iterations and a number of early outs for optimization.
local a = {1,2,3,4,5,6,7,8,9}
local b = {2,4,6,8}
local result1 = filter(a, b)
print(table.concat(result1, ", ")) -- 1, 3, 5, 7, 9
local c = {"a", "b", "c", "d"}
local d = {"c", "d"}
local result2 = filter(c, d)
print(table.concat(result2, ", ")) -- "a", "b"
I see similar answers to this question given in different programming languages like Haskell and Python but all of them use build-in functionality that Lua doesn't have, so please don't mark this question as duplicate.
Let's say i have two tables like bellow:
table1 = {A,B,C}
table2 = {D,E,F}
I would like to find all unique ways of matching the items from two tables, the answer should be (in informal notation):
AD,BE,CF
AD,BF,CE
AE,BD,CF
AE,BF,CD
AF,BD,CE
AF,BE,CD
so the answer will store in a table that table[1] would be {{A, D}, {B, E}, {C, F}} and so on.
tables length can be anything but both will be the same size.
we can get all shuffles via induction (not the fastest way, but pretty easy to write/understand)
local function deepcopy(orig)
local copy
if type(orig) == 'table' then
copy = {}
for orig_key, orig_value in next, orig, nil do
copy[deepcopy(orig_key)] = deepcopy(orig_value)
end
setmetatable(copy, deepcopy(getmetatable(orig)))
else
copy = orig
end
return copy
end
local function get_shuffles(N)
if N == 1 then
return {{1}}
end
local shuffles = get_shuffles(N-1)
local result = {}
for index = 1, #shuffles do
local shuffle = shuffles[index]
for position = 1, #shuffle do
local new_shuffle = deepcopy(shuffle)
table.insert(new_shuffle, position, N)
table.insert(result, new_shuffle)
end
local new_shuffle = deepcopy(shuffle)
table.insert(new_shuffle, N)
table.insert(result, new_shuffle)
end
return result
end
table1 = {"A", "B", "C"}
table2 = {"D","E", "F"}
assert(#table1 == #table2)
local result = {}
local shuffles = get_shuffles(#table1)
for index = 1, #shuffles do
local shuffle = shuffles[index]
local part = {}
for i = 1, 3 do
table.insert(part, {})
table.insert(part[i], table1[i])
table.insert(part[i], table2[shuffle[i]])
end
table.insert(result, part)
end
for index = 1, #result do
print(result[index][1][1], result[index][1][2], result[index][2][1], result[index][2][2], result[index][3][1], result[index][3][2])
end
function get_all_combinations(arr1, arr2)
local n, e, all_comb = #arr1, {}, {}
for j = 1, n do
e[j] = arr2[j]
end
local function generate(m)
if m <= 1 then
local comb = {}
all_comb[#all_comb + 1] = comb
for j = 1, n do
comb[j] = arr1[j]..e[j] -- it should be {arr1[j], e[j]} to fulfill your requirements
end
else
for j = 1, m do
generate(m - 1)
local k = j < m and m % 2 == 1 and 1 or j
e[k], e[m] = e[m], e[k]
end
end
end
generate(n)
return all_comb
end
for i, v in ipairs(get_all_combinations({"A", "B", "C"}, {"D", "E", "F"})) do
print(i, table.concat(v, ";"))
end
An alternate way of doing it is with the following code. This was written to help with a game (Typeshift) to discover all possible combinations of variable groups of letters. I've modified it to fit your example, though.
-- table array: { {1, 2}, {3, 4}, {5, 6} }
-- Should return { 135, 136, 145, 146, 235, 236, 245, 246 }
--
-- This uses tail recursion so hopefully lua is smart enough not to blow the stack
function arrayCombine(tableArray)
-- Define the base cases
if (tableArray == nil) then
return nil
elseif (#tableArray == 0) then
return {}
elseif (#tableArray == 1) then
return tableArray[1]
elseif (#tableArray == 2) then
return arrayCombine2(tableArray[1], tableArray[2])
end -- if
-- We have more than 2 tables in the input parameter. We want to pick off the *last*
-- two arrays, merge them, and then recursively call this function again so that we
-- can work our way up to the front.
local lastArray = table.remove(tableArray, #tableArray)
local nextToLastArray = table.remove(tableArray, #tableArray)
local mergedArray = arrayCombine2(nextToLastArray, lastArray)
table.insert(tableArray, mergedArray)
return arrayCombine(tableArray)
end -- arrayCombine
function arrayCombine2(array1, array2)
local mergedArray = {}
for _, elementA in ipairs(array1) do
for _, elementB in ipairs(array2) do
table.insert(mergedArray, elementA .. elementB)
end -- for
end -- for
return mergedArray
end -- arrayCombine2
-- You can set it up this way:
combinedArray = {}
table.insert(combinedArray, {"A", "B", "C"})
table.insert(combinedArray, {"D", "E", "F"})
for i,v in ipairs(arrayCombine(combinedArray)) do
print(i,v)
end
-- Or go this way, which may be somewhat cleaner:
for i,v in ipairs(arrayCombine({{"A", "B", "C"}, {"D", "E", "F"}})) do
print(i,v)
end
Either way, it produces the results you're looking for.
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
Using Lua (5.1) I would like to fill the table with functions which return several values. Unfortunately, due to Lua specification such function call will only be expanded for the last one.
function get2() return 1, 2 end
local t = { get2(), get2() }
for _,v in pairs(t) do print(v) end
Returns: 1, 1, 2
Is there any way of doing this besides
table = {};
res1, res2 = get2();
table[#table + 1] = res1;
table[#table + 1] = res2
or some other convoluted technique?
No, there is no direct way to do this.
But you can simplify the code with a helper function.
function get2() return 1, 2 end
function appendMultiple(t, ...)
for i=1, select('#', ...) do
t[#t+1] = select(i, ...)
end
end
local t = { }
appendMultiple(t, get2())
appendMultiple(t, get2())
for _,v in pairs(t) do print(v) end
--> 1 2 1 2
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