How to pass table to a function without first element? - lua

I'm trying to create a function that receives a table of strings and parses the table to other function based on its first element.
My Code :
fruits = {}
function addToFruits(t)
print(#t)
end
function parseTable(t)
if t[1] == "fruits" then
addToFruits(table.remove(t, 1)) --pass only {"apple", "banana"}
end
end
parseTable({"fruits", "apple", "banana"})
The Result I get :
6
The Result I expect :
2
How to properly parse the table without the first element?

The return value from table.remove is the removed element ("fruits" )
The object is a string and has length 6, explaining the answer your code is getting.
If you wanted the right answer 2, then the following code will do it.
fruits = {}
function addToFruits(t)
print(#t)
end
function parseTable(t)
if t[1] == "fruits" then
table.remove(t, 1)
addToFruits( t ) --pass only {"apple", "banana"}
end
end
parseTable({"fruits", "apple", "banana"})
Obviously this damages the original table, and depending on use, would need either a table copy - there are various articles on that.
In preference, I would use a structure such as ...
message = { type = "fruits", data = { "apple", "banana" } }
Allowing for the data to be separated from the message type.
The new code would look like....
fruits = {}
function addToFruits(t)
print(#t)
end
function parseTable(t)
if t.type == "fruits" then
addToFruits( t.data ) --pass only {"apple", "banana"}
end
end
message = { type = "fruits", data = { "apple", "banana" } }
parseTable( message )

The table.remove function removes (and returns) an element from a given position in an array. ref
function parseTable(t)
if t[1] == "fruits" then
local removed = table.remove(t, 1)
print(removed) -- fruits
addToFruits(t) -- fruits removed and will pass {"apple", "banana"}
end
end
The answer 6 was the length of "fruits" which table.remove(t, 1) will return

Related

LUA, Unpack all the hierarchy of a Nested Table and store and return Table with all the elements at the same hierarchy

I have a nested array, for example,
someTable = {"value1", "value2", {"value3a", "value3b", {"value4a", "value4b", "value4c"}}
and trying to find a way to get all of these different elements at different hierarchies to actually come down to a single hierarchy
expected results,
newTable = {"value1", "value2", "value3a", "value3b", "value4a", "value4b", "value4c"}
I've found this below code that actually prints all those elements, but I couldn't find a way to make it into a new table with one hierarchy an return it
function DeepPrint (e)
-- if e is a table, we should iterate over its elements
if type(e) == "table" then
for k,v in pairs(e) do -- for every element in the table
print(k)
DeepPrint(v) -- recursively repeat the same procedure
end
else -- if not, we can just print it
print(e)
end
end
I agree with what Doj is saying, but you don't need two functions to do that.
Just recursively call initial function, like you did with your print example above.
#! /usr/bin/env lua
someTable = {"value1", "value2", {"value3a", "value3b", {"value4a", "value4b", "value4c"}}}
function flatten( item, result )
local result = result or {} -- create empty table, if none given during initialization
if type( item ) == 'table' then
for k, v in pairs( item ) do
flatten( v, result )
end
else
result[ #result +1 ] = item
end
return result
end
newTable = flatten( someTable )
for i = 1, #newTable do print( newTable[i] ) end
Instead of printing the elements just insert them to result table:
function flattenRecursive(e, result)
-- if e is a table, we should iterate over its elements
if type(e) == "table" then
for k,v in pairs(e) do -- for every element in the table
flattenRecursive(v, result) -- recursively repeat the same procedure
end
else -- if not, we can just put it to the result
table.insert(result, e)
end
end
function flatten (e)
local result = {}
flattenRecursive(e, result)
return result
end
Test:
example = {"value1", "value2", {"value3a", "value3b", {"value4a", "value4b", "value4c"}}}
example_result = flatten(example)
for k,v in pairs(example_result) do
print(v)
end

How to get the size of an array in lua

I'm trying get the size of an array and loop in it. I tried use the getn function, but it didn't work.
Here is my code:
results =
{
address= "Address 1",
type_address= "RESIDENCIAL",
phone= "654620460",
email= "email1#email.com"
},
{
address= "Address 2",
type_address= "COMERCIAL",
phone= "604654650",
email= "email1#email.com"
}
for i = 0, table.getn(results), 1 do
if results[i].type_address == "RESIDENCIAL" then
phone = results[i].phone
email = results[i].email
break
else
phone = results[1].phone
email = results[1].email
end
end
print (phone)
print (email)
To get the size of the table use #tbl for arrays.
You forgot to wrap items into {}. For now you assigned results to table with Address 1, table with Address 2 is ignored because you didn't assign it to anything (due to mistake)
Wrap it like this:
results = {
-- items here
}
Quick note: table.getn is deprecated and identical to #tbl, you can also use
for k,v in ipairs(results) do.
Third parameter of for statement is optional and defaults to 1.
for i = 0, #results do
if results[i].type_address == "RESIDENCIAL" then
-- etc
end
-- or
for k, v in ipairs(results) do
if v.type_address == "RESIDENCIAL" then
-- etc
end
I use...
function(len) local incr=0 for _ in pairs(len) do incr=incr+1 end return incr end
...as a metamethod __index.len for table key counting. Then...
> test_table={'1',two='2',pi=math.pi,popen=io.popen}
> setmetatable(test_table,{__index={len=function(len) local incr=0 for _ in pairs(len) do incr=incr+1 end return incr end}})
table: 0x565aa850
> test_table:len()
4
...it count mixed numbered and named keys correctly. Where...
> #test_table
1
...doesnt.

Can't figure out this table arrangement

--The view of the table
local originalStats = {
Info = {Visit = false, Name = "None", Characters = 1},
Stats = {Levels = 0, XP = 0, XP2 = 75, Silver = 95},
Inventory = {
Hats = {"NoobHat"},
Robes = {"NoobRobe"},
Boots = {"NoobBoot"},
Weapons = {"NoobSword"}
}
}
local tempData = {}
--The arrangement here
function Module:ReadAll(player)
for k,v in pairs(tempData[player]) do
if type(v) == 'table' then
for k2, v2 in pairs(v) do
print(k2) print(v2)
if type(v2) == 'table' then
for k3, v3 in pairs(v2) do
print(k3) print(v3)
end
else
print(k2) print(v2)
end
end
else
print(k) print(v)
end
end
end
I'm sorry, but I can't seem to figure out how to arrange this 'ReadAll' function to where It'll show all the correct stats in the right orders.
The output is something like this:
Boots
table: 1A73CF10
1
NoobBoot
Weapons
table: 1A7427F0
1
NoobSword
Robes
table: 1A743D50
1
NoobRobe
Hats
table: 1A73C9D0
1
NoobHat
XP2
75
XP2
75
Levels
2
Levels
2
XP
0
XP
0
Here's a way to print all the elements without double or table reference values showing up.
As the name states, this function will print all the elements within a table, no matter how many nested tables there are inside it. I don't have a way to order them at the moment, but I'll update my answer if I find a way. You can also get rid of the empty spaces in the print line, I just used it so it would look neater. Let me know if it works.
function allElementsInTable(table)
for k,v in pairs(table) do
if type(table[k]) == 'table' then
print(k .. ":")
allElementsInTable(v)
else
print(" " .. k .. " = " .. tostring(v))
end
end
end
--place the name of your table in the parameter for this function
allElementsInTable(originalStats)
After more experimenting, I got this, if anyone wants it, feel free to use it.
tempData = { Info = {Visit = false, Name = 'None'},
Stats = {LVL = 0, XP = 0, Silver = 75},
Inventory = { Armors = {'BasicArmor'},
Weapons = {'BasicSword'} }
}
function Read()
for i, v in pairs(tempData['Info']) do
print(i..'\t',v)
end
----------
for i2, v2 in pairs(tempData['Stats']) do
print(i2..'\t',v2)
end
----------
for i3, v3 in pairs(tempData['Inventory']) do
print(i3..':')
for i4, v4 in pairs(v3) do
print('\t',v4)
end
end
end
Read()
Don't expect table's fields to be iterated with pairs() in some specific order. Internally Lua tables are hashtables, and the order of fields in it is not specified at all. It will change between runs, you can't have them iterated in the same order as they were filled.Only arrays with consecutive integer indices will maintain the order of their elements.

Finding duplicates in a multi-dimensional table

A slightly altered version of the below permitted me to filter unique field values out of a multi-dimensional table (dictionary style).
[ url ] http://rosettacode.org/wiki/Remove_duplicate_elements#Lua
items = {1,2,3,4,1,2,3,4,"bird","cat","dog","dog","bird"}`
flags = {}
io.write('Unique items are:')
for i=1,#items do
if not flags[items[i]] then
io.write(' ' .. items[i])
flags[items[i]] = true
end
end
io.write('\n')`
What I'm lost at is what 'if not ... then ... end' part actually does. To me this is sillyspeak but hey, it works ;-) Now i want to know what happens under the hood.
I hope multi-dimensional does not offend anyone, I'm referring to a table consisting of multiple row containing multiple key-value pairs on each row.
Here's the code i'm using, no brilliant adaptation but good enough to filter unique values on a fieldname
for i=1,#table,1 do
if not table2[table[i].fieldname] then
table2[table[i].fieldname] = true
end
end
for k,v in pairs(table2) do
print(k)
end
function findDuplicates(t)
seen = {} --keep record of elements we've seen
duplicated = {} --keep a record of duplicated elements
for i = 1, #t do
element = t[i]
if seen[element] then --check if we've seen the element before
duplicated[element] = true --if we have then it must be a duplicate! add to a table to keep track of this
else
seen[element] = true -- set the element to seen
end
end
return duplicated
end
The logic behind the if seen[element] then, is that we check if we've already seen the element before in the table. As if they key doesn't exist nill will be returned which is evaluated which is false (this is not the same as boolean false, there are two types of false in lua!).
You can use this function like so:
t = {'a','b','a','c','c','c','d'}
for key,_ in pairs(findDuplicates(t)) do
print(key)
end
However that function won't work with multidimensional tables, this one will however:
function findDuplicates(t)
seen = {} --keep record of elements we've seen
duplicated = {} --keep a record of duplicated elements
local function traverse(subt)
for i=1, #subt do
element = subt[i]
if type(element) == 'table' then
traverse(element)
else
if seen[element] then
duplicated[element] = true
else
seen[element] = true
end
end
end
end
traverse(t)
return duplicated
end
Example useage:
t = {'a',{'b','a'},'c',{'c',{'c'}},'d'}
for k,_ in pairs(findDuplicates(t)) do
print(k)
end
Outputs
a
c
t = {a='a',b='b',c='c',d='c',e='a',f='d'}
function findDuplicates(t)
seen = {}
duplicated = {}
for key,val in pairs(t) do
if seen[val] then
duplicated[val] = true
else
seen[val] = true
end
end
return duplicated
end
This works the same way as before but checks if the same value is associated with a different key and if so, makes note of that value as being duplicated.
Eventually this is the code which worked for me. I've been asked to post it as a separate answer so here goes.
for i=1,#table1,1 do
if not table2[table1[i].fieldname] then
table2[table1[i].fieldname] = true
end
end
for k,v in pairs(table2) do
print(k)
end

Comparing two index tables by index-value in lua

I'm attempting to compare two tables of equal length with a function, since I don't know of any other way to do so. However, with the following function, it fails to register, and I've no clue why. I'm hoping someone can provide insight to this problem or has a better way of comparing the two tables.
The tables are being populated with the following code:
str = "parameters determined by program (all digits)"
tableone = {}
for word in str:gmatch("%d") do table.insert(tableone,word) end
It's identical for both tables, except, of course, the individual table names. The tables are being populated properly, and display properly when I print them. Here are two tables for the sake of this question:
tableone = {}
tabletwo = {}
for i=1,4 do table.insert(tableone, i) end
for i=1,4 do table.insert(tabletwo, i) end
Obviously, these two tables are going to be equal to each other. The function I wrote to compare the index tables is as follows:
function comparetables(t1, t2)
matchct = 0
for i=1,#t1 do
if t1[i] == t2[i] then
matchct = matchct + 1
end
if matchct == #t1 then
return true
end
end
I tried doing
print(comparetables(tableone,tabletwo))
to see if it'll print "true" but no luck. To me, it seems like it should work without a problem. Yet it doesn't. What am I missing? I've tried searching for something like a table.compare function that someone may have already written, but no such luck in finding one. Thanks for any suggestions!
Additional information:
The reason I'm comparing tables is for a mastermaind-type game. That means the following three rules must apply when comparing tables. The function I created was to just get me started, thinking I could work from there.
When comparing the tables, if the numbers match, Ccount increases by 1.
When comparing tables, if the value exists in a different index position, increment Pcount by 1
For example, with a table of values {1, 3, 3, 4} and a guess of {4, 4, 3, 1}, it would return Pcount of 2 (the one 4 and the 1) and a Ccount of 1 (the three in the third position). I think one of the hardest parts is going to be getting the comparison to recognize that the second 4 in the guess should not increment the Pcount at all.
A slight variant on your code that should work is:
function comparetables(t1, t2)
if #t1 ~= #t2 then return false end
for i=1,#t1 do
if t1[i] ~= t2[i] then return false end
end
return true
end
However I use something more like this: It checks the types of the arguments, their metatables, and a few other cases.
-- This is not clever enough to find matching table keys
-- i.e. this will return false
-- recursive_compare( { [{}]:1 }, { [{}]:1 } )
-- but this is unusual enough for me not to care ;)
-- It can also get stuck in infinite loops if you use it on
-- an evil table like this:
-- t = {}
-- t[1] = t
function recursive_compare(t1,t2)
-- Use usual comparison first.
if t1==t2 then return true end
-- We only support non-default behavior for tables
if (type(t1)~="table") then return false end
-- They better have the same metatables
local mt1 = getmetatable(t1)
local mt2 = getmetatable(t2)
if( not recursive_compare(mt1,mt2) ) then return false end
-- Check each key-value pair
-- We have to do this both ways in case we miss some.
-- TODO: Could probably be smarter and not check those we've
-- already checked though!
for k1,v1 in pairs(t1) do
local v2 = t2[k1]
if( not recursive_compare(v1,v2) ) then return false end
end
for k2,v2 in pairs(t2) do
local v1 = t1[k2]
if( not recursive_compare(v1,v2) ) then return false end
end
return true
end
Here's an example of it in use:
print( recursive_compare( {1,2,3,{1,2,1}}, {1,2,3,{1,2,1}} ) ) -- prints true
print( recursive_compare( {1,2,3,{1,2,1}}, {2,2,3,{1,2,3}} ) ) -- prints false
If you're comparing objects that are more objecty than tabley in an Object oriented sense, then I'd look at implementing the functions in the lua OO way.
Something like this should do the trick:
GameState = {}
GameState.mt = {}
GameState.mt.fns = {}
GameState.mt.__index = GameState.mt.fns
function GameState.new(a,b,c,d)
-- TODO: put argument checks here...
local retval = {}
retval[1] = a
retval[2] = b
retval[3] = c
retval[4] = d
setmetatable(retval, GameState.mt)
return retval
end
function GameState.mt.fns.print( self )
print(" GameState: ", self[1], self[2], self[3], self[4] )
end
function GameState.mt.__tostring( self )
return "GameState: "..self[1].." "..self[2].." "..self[3].." "..self[4]
end
function GameState.mt.__eq(self, other)
-- Check it's actually a GameState, and all its bits match
return getmetatable(other)==GameState.mt and
(self[1] == other[1]) and
(self[2] == other[2]) and
(self[3] == other[3]) and
(self[4] == other[4])
end
Then you'd use it like this:
state1 = GameState.new(1,2,3,4)
state2 = GameState.new(1,2,3,4)
print("State 1 is:")
state1:print()
print("State 2 is:")
print(state2)
print( "state1 == state2 : ", state1 == state2 )
print( "Changing state 2")
state2[1]=2
print( "state1 == state2 : ", state1 == state2 )

Resources