How to get the size of an array in lua - 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.

Related

How to pass table to a function without first element?

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

Searching in Redis evaluating Lua script

I'm trying to search for field value in hash using Lua script and I'm doing something wrong :)
I have key "articles" which is zset holding article IDs and keys article:n where "n" is the article number.
The following script:
local ids = redis.call("zrange", 'articles', '0', '-1')
local ret = {}
for k, id in pairs(ids) do
local row = redis.call("hgetall", "article:"..id)
ret[k] = row
end
return ret
returns this:
1) 1) "slug"
2) "first-title"
3) "title"
4) "first title"
2) 1) "slug"
2) "second-title"
3) "title"
4) "second title"
Than I'm trying to include condition to return only keys containing string "second" in title but it returns nothing.
local ids = redis.call("zrange", 'articles', '0', '-1')
local ret = {}
for k, id in pairs(ids) do
local row = redis.call("hgetall", "article:"..id)
if (string.find(row[4], "second")) then
ret[k] = row
end
end
return ret
Please could you help me?
The table you returned from lua, must be an array whose index staring from 1.
However, In your example, only the second article matches the condition, and its index is 2. So you are, in fact, setting the table as: ret[2] = row. Since the returned table is NOT an array whose index starting from 1, Redis takes it as an empty array, and you get nothing.
Solution:
local ids = redis.call("zrange", 'articles', '0', '-1')
local ret = {}
local idx = 1; -- index starting from 1
for k, id in pairs(ids) do
local row = redis.call("hgetall", "article:"..id)
if (string.find(row[4], "second")) then
ret[idx] = row -- set table
idx = idx + 1 -- incr index by 1
end
end
return ret
Try this condition
if (string.find(row[4], "second") ~= nil) then

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.

redis: "Multi Bulk Reply" -> lua table

ti have a sorted-set like this:
|key |score |member
zadd mykey 100 event:1
zadd mykey 101 event:2
zadd mykey 102 event:3
now i use a lua-script to return a sub-set from a given score-range
var result = redis.call('zrangebyscore', 'mykey', start, stop, 'WITHSCORES')
what would the result-Table look like in lua-script? (since i can not debug, i have to ask)
From the redis-doc: Redis multi bulk reply -> Lua table (may have other Redis data types nested) - this is all the info i can find.
would it be like:
result = { 'event:1', 100, 'event:2', 101, 'event:3', 102 }
or like
result = { 100, 'event:1', 101, 'event:2', 102, 'event:3' }
or different?
The result from a zrangebyscore ... withscores -- or any read from a sorted set with scores, really -- will be returned as a lua table looking like this:
result = { "event:1", "100", "event:2", "101" }
Value first, score second. Values and scores are both strings.
Assuming what you are using can write to standard output, you could add a dump function and output the table format.
I use
function dump (tt, label,indent, done)
if debug == true then
if label == nil then
label = 'Dump'
end
done = done or {}
indent = indent or 0
if type(tt) == "table" then
if indent == 0 then
io.write(string.rep (" ", indent))
io.write(label..'\n')
end
for key, value in pairs (tt) do
io.write(string.rep (" ", indent)) -- indent it
if type (value) == "table" and not done [value] then
done [value] = true
io.write(string.format("[%s] => table\n", tostring (key)));
io.write(string.rep (" ", indent+4)) -- indent it
io.write("(\n");
dump (value, tostring(key),indent + 7, done)
io.write(string.rep (" ", indent+4)) -- indent it
io.write(")\n");
else
io.write(string.format("[%s] => %s\n",
tostring (key), tostring(value)))
end
end
else
io.write(tostring(label)..':'..tostring(tt))
end
else
return
end
end
So for your example you would simply add
debug = true
dump(var,'redis-table')

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