redis: "Multi Bulk Reply" -> lua table - lua

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')

Related

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.

Constructing Key/Value Table in Lua

I'm trying to build a script for a MUD I play that will create a table to keep track of average xp for each mob. I'm having trouble with the syntax of checking whether an element in a table exists and if not creating it. I tried something like this but keep getting: attempt to index field '?' (a nil value)
mobz_buried = {
{mob = "troll", quantity = 2}
{mob = "warrior", quantity = 1}
{mob = "wizard", quantity = 1}} -- sample data
number_of_mobz_buried = 4
xp_from_bury = 2000 -- another script generates these values, these are all just examples
xp_per_corpse = xp_from_bury / number_of_mobz_buried
for _, v in ipairs(mobz_buried) do
if type(mobz[v].kc) == "variable" then -- kc for 'kill count', number of times killed
mobz[v].kc = mobz[v].kc + 1 -- if it exists increment kc
else
mobz[v].kc = 1 -- if it doesn't exist create a key value that matches the mobs name and make the kc 1
end
if type(mobz[v].xp) == "variable" then -- xp for average experience points
mobz[v].xp = (((mobz[v].kc - 1) * mobz[v].xp + xp_per_corpse)/mobz[v].kc) -- just my formula to find the average xp over a range of differant buries
else
mobz[v].xp = xp_per_corpse -- if it doesn't exist create the table just like before
end
end
I'm trying to end up with mobz.troll = {kc, xp}, mobz.warrior = {kc, xp}, mobz.wizard = {kc, xp} and the ability to add more key values based off of the names mobz_buried gives me.
Based on extra info from your comments, it sounds like you didn't construct a table for mobz. Try this:
local mobz = {}
for _, v in ipairs(mobz_buried) do
mobz[v.mob] = mobz[v.mob] or {}
mobz[v.mob].kc = (mobz[v.mob].kc or 0) + 1
-- etc...
end

lua - checking for duplicate data in a string

I have the following string data that I receive as input:
"route1,1234,1,no~,,route2,1234,1,no~,"
It represents two "records" of data... where each record has 4 fields.
I've built code to parse this string into it's individual columns / fields.
But the part that isn't working is when I test to see if I have any duplicates in field 2. Field 2 is the one that currently has "1234" as the value.
Here's the code:
function string:split(delimiter)
local result = { }
local from = 1
local delim_from, delim_to = string.find( self, delimiter, from )
while delim_from do
table.insert( result, string.sub( self, from , delim_from-1 ) )
from = delim_to + 1
delim_from, delim_to = string.find( self, delimiter, from )
end
table.insert( result, string.sub( self, from ) )
return result
end
local check_for_duplicate_entries = function(route_data)
local route
local route_detail = {}
local result =true
local errtxt
local duplicate = false
print("received :" ..route_data)
route = string.gsub(route_data, "~,,", "~")
route = route:sub(1,string.len(route)-2)
print("route :" ..route)
-- break up in to an array
route = string.split(route,"~")
for key, value in pairs(route) do
route_detail[key] = string.split(value,",")
end
local list_of_second_column_only = {}
for key,value in pairs(route_detail) do
local temp = value[2]
print(temp .. " - is the value I'm checking for")
if list_of_second_column_only[temp] == nil then
print("i dont think it exists")
list_of_second_column_only[key] = value[2]
print(list_of_second_column_only[key])
else
--found a duplicate.
return true
end
end
return false
end
print(check_for_duplicate_entries("route1,1234,1,no~,,route2,1234,1,no~,"))
I think where I'm going wrong is the test:
if list_of_second_column_only[temp] == nil then
I think I'm checking for key with the value temp instead of a value with the value that temp contains. But I don't know how to fix the syntax.
Also, I'm wondering if there's a more efficient way to do this.
The number of "records" i receive as input is dynamic / unknown, as is the value of the second column in each record.
Thanks.
EDIT 1
The post I was trying to use as a reference is: Search for an item in a Lua list
In the answer, they show how to test for a record in the table by value, instead of looping through the entire table...
if items["orange"] then
-- do something
end
I was playing around to try and do something similar...
This should be a bit more efficient with only one table creation and less regex matching.
The match does require that you're only interested in dups in the second field.
local function check_for_duplicate_entries(route_data)
assert(type(route_data)=="string")
local field_set = {}
for route in route_data:gmatch"([^~]*)~,?,?" do
local field = route:match",([^,]*)"
if field_set[field] then
return true
else
field_set[field] = true
end
end
return false
end
Try this. It's doing the check on the value of the second field.
I haven't looked at the efficiency.
if list_of_second_column_only[value[2]] == nil then
print("i dont think it exists")
list_of_second_column_only[value[2]] = true
print(list_of_second_column_only[value[2]])
else
--found a duplicate.
return true
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