Lua table.toString(tableName) and table.fromString(stringTable) functions? - serialization

I am wanting to convert a 2d lua table into a string, then after converting it to a string convert it back into a table using that newly created string. It seems as if this process is called serialization, and is discussed in the below url, yet I am having a difficult time understanding the code and was hoping someone here had a simple table.toString and table.fromString function
http://lua-users.org/wiki/TableSerialization

I am using the following code in order to serialize tables:
function serializeTable(val, name, skipnewlines, depth)
skipnewlines = skipnewlines or false
depth = depth or 0
local tmp = string.rep(" ", depth)
if name then tmp = tmp .. name .. " = " end
if type(val) == "table" then
tmp = tmp .. "{" .. (not skipnewlines and "\n" or "")
for k, v in pairs(val) do
tmp = tmp .. serializeTable(v, k, skipnewlines, depth + 1) .. "," .. (not skipnewlines and "\n" or "")
end
tmp = tmp .. string.rep(" ", depth) .. "}"
elseif type(val) == "number" then
tmp = tmp .. tostring(val)
elseif type(val) == "string" then
tmp = tmp .. string.format("%q", val)
elseif type(val) == "boolean" then
tmp = tmp .. (val and "true" or "false")
else
tmp = tmp .. "\"[inserializeable datatype:" .. type(val) .. "]\""
end
return tmp
end
the code created can then be executed using loadstring(): http://www.lua.org/manual/5.1/manual.html#pdf-loadstring if you have passed an argument to 'name' parameter (or append it afterwards):
s = serializeTable({a = "foo", b = {c = 123, d = "foo"}})
print(s)
a = loadstring(s)()

The code lhf posted is a much simpler code example than anything from the page you linked, so hopefully you can understand it better. Adapting it to output a string instead of printing the output looks like:
t = {
{11,12,13},
{21,22,23},
}
local s = {"return {"}
for i=1,#t do
s[#s+1] = "{"
for j=1,#t[i] do
s[#s+1] = t[i][j]
s[#s+1] = ","
end
s[#s+1] = "},"
end
s[#s+1] = "}"
s = table.concat(s)
print(s)
The general idea with serialization is to take all the bits of data from some data structure like a table, and then loop through that data structure while building up a string that has all of those bits of data along with formatting characters.

How about a JSON module? That way you have also a better exchangeable data. I usually prefer dkjson, which also supports utf-8, where cmjjson won't.

Under the kong works this
local cjson = require "cjson"
kong.log.debug(cjson.encode(some_table))
Out of the kong should be installed package lua-cjson https://github.com/openresty/lua-cjson/

Here is a simple program which assumes your table contains numbers only. It outputs Lua code that can be loaded back with loadstring()(). Adapt it to output to a string instead of printing it out. Hint: redefine print to collect the output into a table and then at the end turn the output table into a string with table.concat.
t = {
{11,12,13},
{21,22,23},
}
print"return {"
for i=1,#t do
print"{"
for j=1,#t[i] do
print(t[i][j],",")
end
print"},"
end
print"}"

Assuming that:
You don't have loops (table a referencing table b and b referencing a)
Your tables are pure arrays (all keys are consecutive positive integers, starting on 1)
Your values are integers only (no strings, etc)
Then a recursive solution is easy to implement:
function serialize(t)
local serializedValues = {}
local value, serializedValue
for i=1,#t do
value = t[i]
serializedValue = type(value)=='table' and serialize(value) or value
table.insert(serializedValues, serializedValue)
end
return string.format("{ %s }", table.concat(serializedValues, ', ') )
end
Prepend the string resulting from this function with a return, store it on a .lua file:
-- myfile.lua
return { { 1, 2, 3 }, { 4, 5, 6 } }
You can just use dofile to get the table back.
t = dofile 'myfile.lua'
Notes:
If you have loops, then you will have
to handle them explicitly - usually with an extra table to "keep track" of repetitions
If you don't have pure arrays, then
you will have to parse t differently,
as well as handle the way the keys are rendered (are they strings? are they other tables? etc).
If you have more than just integers
and subtables, then calculating
serializedValue will be more
complex.
Regards!

I have shorter code to convert table to string but not reverse
function compileTable(table)
local index = 1
local holder = "{"
while true do
if type(table[index]) == "function" then
index = index + 1
elseif type(table[index]) == "table" then
holder = holder..compileTable(table[index])
elseif type(table[index]) == "number" then
holder = holder..tostring(table[index])
elseif type(table[index]) == "string" then
holder = holder.."\""..table[index].."\""
elseif table[index] == nil then
holder = holder.."nil"
elseif type(table[index]) == "boolean" then
holder = holder..(table[index] and "true" or "false")
end
if index + 1 > #table then
break
end
holder = holder..","
index = index + 1
end
return holder.."}"
end
if you want change the name just search all compileTable change it to you preferred name because this function will call it self if it detect nested table but escape sequence I don't know if it work
if you use this to create a lua executable file that output the table it will ge compilation error if you put new line and " sequence
this method is more memory efficient
Note:
Function not supported
User data I don't know

My solution:
local nl = string.char(10) -- newline
function serialize_list (tabl, indent)
indent = indent and (indent.." ") or ""
local str = ''
str = str .. indent.."{"
for key, value in pairs (tabl) do
local pr = (type(key)=="string") and ('["'..key..'"]=') or ""
if type (value) == "table" then
str = str..nl..pr..serialize_list (value, indent)..','
elseif type (value) == "string" then
str = str..nl..indent..pr..'"'..tostring(value)..'",'
else
str = str..nl..indent..pr..tostring(value)..','
end
end
str = str:sub(1, #str-1) -- remove last symbol
str = str..nl..indent.."}"
return str
end
local str = serialize_list(tables)
print('return '..nl..str)

Related

Count unknown variables from a table

I have a problem here... if I have a table with few repeated string results. I want to know the value am the ammount of each.
For example. A function return an unknown "letters" and with unknown quantities in quantity
Function () return Table end
Table ={'a','a','c','b','b','a',...}
And I want to get this.
table.a={'a','a','a'}
table.b={'b','b'}
table.c={'c'}
....
....
I have no clue how to solve it...
Write a function, which creates a hash map of these things:
function RepetitionCounter(tInput)
local tCounter = {}
for i, v in ipairs(tInput) do
tCounter[v] = (tCounter[v] or 0) + 1
end
return tCounter
end
which you'll use as follows:
local tData = {'a','a','c','b','b','a',...}
local tCounts = RepetitionCounter(tData)
and the table tCounts would be as follows:
tCounts.a = 3
tCounts.b = 2
tCounts.c = 1
Modifying the function above by just a little, you can get the desired output. Replace the following line:
tCounter[v] = (tCounter[v] or 0) + 1
with
if not tCounter[v] then
tCounter[v] = {}
else
table.insert(tCounter[v], v)
end

Differences between two tables in Lua

I have two tables in lua (In production, a has 18 elements and b has 8):
local a = {1,2,3,4,5,6}
local b = {3,5,7,8,9}
I need to return 'a' omitting any common elements from 'b' -- {1,2,4,6} similar to the ruby command a-b (if a and b were arrays).
The best lua logic I have been able to come up with is:
local function find(a, tbl)
for _,a_ in ipairs(tbl) do if a_==a then return true end end
end
function difference(a, b)
local ret = {}
for _,a_ in ipairs(a) do
if not find(a_,b) then table.insert(ret, a_) end
end
return ret
end
local a = {1,2,3,4,5,6}
local b = {3,5,7,8,9}
local temp = {}
temp = difference(a,b)
print(temp[1],temp[2],temp[3],temp[4])
I need to loop through these table comparison pretty quick (min 10K times a second in production). Is there a cleaner way to do this?
======
This is part of a redis server side script and I have to protect my Redis CPU. Outside of a clean Lua process I have two other options:
1.Create two redis temp keys then run sinter for a big(O) of 42
18 sadd(a)
8 sadd(b)
16 sinter(a,b)
2.Return both a and b to ruby do the array comparison and send back the result.
Network cost of the back and fourth of a few thousand connections a second will be a drain on resources.
Try this:
function difference(a, b)
local aa = {}
for k,v in pairs(a) do aa[v]=true end
for k,v in pairs(b) do aa[v]=nil end
local ret = {}
local n = 0
for k,v in pairs(a) do
if aa[v] then n=n+1 ret[n]=v end
end
return ret
end
You could do this (not tested):
function difference(a, b)
local ai = {}
local r = {}
for k,v in pairs(a) do r[k] = v; ai[v]=true end
for k,v in pairs(b) do
if ai[v]~=nil then r[k] = nil end
end
return r
end
If you can modify a then it is even shorter:
function remove(a, b)
local ai = {}
for k,v in pairs(a) do ai[v]=true end
for k,v in pairs(b) do
if ai[v]~=nil then a[k] = nil end
return r
end
If your tables are sorted you could also do a parallel sweep of the two tables together, something like the following pseudo code:
function diff(a, b)
Item = front of a
Diff = front of b
While Item and Diff
If Item < Diff then
Item is next of a
Else if Item == Diff then
remove Item from a
Item = next of a
Diff = next of b
Else # else Item > Diff
Diff = next of b
This doesn't use any extra tables. Even if you want new table instead of in-place diff, only one new table. I wonder how it would compare to the hash table method (remove).
Note that it doesn't matter how many times you loop, if a and b are small then there will be no major difference between these and your alg. You'll need at least 100 items in a and in b, maybe even 1000.
Maybe something like that:
function get_diff (t1, t2)
local diff = {}
local bool = false
for i, v in pairs (t1) do
if t2 and type (v) == "table" then
local deep_diff = get_diff (t1[i], t2[i])
if deep_diff then
diff[i] = deep_diff
bool = true
end
elseif t2 then
if not (t1[i] == t2[i]) then
diff[i] = t1[i] .. ' -- not [' .. t2[i] .. ']'
bool = true
end
else
diff[i] = t1[i]
bool = true
end
end
if bool then
return diff
end
end
local t1 = {1, 2, 3, {1, 2, 3}}
local t2 = {1, 2, 3, {1, 2, 4}}
local diff = get_diff (t1, t2)
Result:
diff = {
nil,
nil,
nil,
{
[3] = "3 -- not [4]"
}
}

How do I serialize a table for insertion into a database? [duplicate]

This question already has answers here:
method for serializing lua tables
(5 answers)
Closed 8 years ago.
I would like to serialize a table so that I can insert it into a database and retrieve it later on. How would I do this?
maybe like this https://gist.github.com/rangercyh/5814003
local szStr = ""
function print_lua_table (lua_table, indent)
indent = indent or 0
for k, v in pairs(lua_table) do
if type(k) == "string" then
k = string.format("%q", k)
end
local szSuffix = ""
if type(v) == "table" then
szSuffix = "{"
end
local szPrefix = string.rep(" ", indent)
formatting = szPrefix.."["..k.."]".." = "..szSuffix
if type(v) == "table" then
szStr = szStr..formatting
print_lua_table(v, indent + 1)
szStr = szStr..szPrefix.."},"
else
local szValue = ""
if type(v) == "string" then
szValue = string.format("%q", v)
else
szValue = tostring(v)
end
szStr = szStr..formatting..szValue..","
end
end
end
How to serialize Lua value nicely?
local serialize
do
local num_fmt = '%.17g'
local NaN_serialized = { -- This idea was stolen from lua-nucleo
[num_fmt:format(1/0)] = '1/0',
[num_fmt:format(-1/0)] = '-1/0',
[num_fmt:format(0/0)] = '0/0'
}
local function serialize_table(t, indent)
indent = indent or ''
local new_indent = indent..'\t'
if next(t) == nil then
return '{}'
else
local lines = {}
local function add_line(key)
local ser_key = key
if type(key) ~= 'string' or not key:find'^[%a_][%w_]*$' then
ser_key = '['..serialize(key, new_indent)..']'
end
table.insert(lines,
ser_key..' = '..serialize(t[key], new_indent))
end
local other_keys = {}
local keys = setmetatable({number = {}, string = {}},
{__index = function() return other_keys end})
for k in pairs(t) do
table.insert(keys[type(k)], k)
end
table.sort(keys.number)
table.sort(keys.string)
for _, k in ipairs(keys.number) do
add_line(k)
end
for _, k in ipairs(keys.string) do
add_line(k)
end
for _, k in ipairs(other_keys) do
add_line(k)
end
return '{\n'..new_indent..table.concat(lines, ',\n'..new_indent)
..'\n'..indent..'}'
end
end
function serialize(v, indent)
if type(v) == 'string' then
return ('%q'):format(v)
elseif type(v) == 'boolean' then
return tostring(v)
elseif type(v) == 'nil' then
return tostring(v)
elseif type(v) == 'number' then
return (num_fmt:format(v):gsub('^.*', NaN_serialized))
elseif type(v) == 'table' then
return serialize_table(v, indent)
else
error('Can not serialize '..type(v))
end
end
end
-- What it can:
print(serialize(math.huge))
print(serialize'"What\'s up?"\n\t123')
print(serialize{{}, {{}}})
-- And what it can not:
local t = {}
local tt = {[t] = t}
print(serialize(tt)) -- tt is not a tree, so it was serialized incorrectly

Comparing Basic Strings Exponential Complexity

I may be asking a silly question but I am self teaching myself VBA and I am just stumped and I am not even sure what terms I can use to look up a solution.
I am writing a code that will compare three variables to three other variables then I want to display which variables have changed.
So if x = a but y <> b and z <> c then the output should be b/c
I have worked out a code that works fine
Dim Str As String
If X <> A Then
If Y <> B Then
If Z <> C Then
Str = "a/b/c"
Else
Str = "a/b"
End If
ElseIf Z <> C Then
Str = "a/c"
Else
Str = "a"
End If
ElseIf Y <> B Then
If Z <> C Then
Str = "b/c"
Else
Str = "b"
End If
Else
Str = "c"
End If
But as I increase the number of variables this becomes extremely complex very quickly.
If anyone can help direct me to a simpler method without the exponential complexity I would be very grateful.
Thank you all so much!
You need to test each variable pair independently from each other -- not link them together in one giant If construct tree.
Example:
str = "" 'Start with blank string. Append as required.
If x <> a Then str = str & "a/"
If y <> b Then str = str & "b/"
If z <> c Then str = str & "c/"
'Remove the extra / at the end
If Right(str, 1) = "/" Then str = Left(str, Len(str - 1))
You could put the 2 strings in 2 arrays, and then use a FOR...NEXT construct to loop both arrays. You can use UBound(arValues) to dynamically find out the number of items in the array.
Good luck

groovy closure instantiate variables

is it possible to create a set of variables from a list of values using a closure??
the reason for asking this is to create some recursive functionality based on a list of (say) two three four or five parts
The code here of course doesn't work but any pointers would be helpful.then
def longthing = 'A for B with C in D on E'
//eg shopping for 30 mins with Fiona in Birmingham on Friday at 15:00
def breaks = [" on ", " in ", "with ", " for "]
def vary = ['when', 'place', 'with', 'event']
i = 0
line = place = with = event = ""
breaks.each{
shortline = longthing.split(breaks[i])
longthing= shortline[0]
//this is the line which obviously will not work
${vary[i]} = shortline[1]
rez[i] = shortline[1]
i++
}
return place + "; " + with + "; " + event
// looking for answer of D; C; B
EDIT>>
Yes I am trying to find a groovier way to clean up this, which i have to do after the each loop
len = rez[3].trim()
if(len.contains("all")){
len = "all"
} else if (len.contains(" ")){
len = len.substring(0, len.indexOf(" ")+2 )
}
len = len.replaceAll(" ", "")
with = rez[2].trim()
place = rez[1].trim()
when = rez[0].trim()
event = shortline[0]
and if I decide to add another item to the list (which I just did) I have to remember which [i] it is to extract it successfully
This is the worker part for then parsing dates/times to then use jChronic to convert natural text into Gregorian Calendar info so I can then set an event in a Google Calendar
How about:
def longthing = 'A for B with C in D on E'
def breaks = [" on ", " in ", "with ", " for "]
def vary = ['when', 'place', 'with', 'event']
rez = []
line = place = with = event = ""
breaks.eachWithIndex{ b, i ->
shortline = longthing.split(b)
longthing = shortline[0]
this[vary[i]] = shortline[1]
rez[i] = shortline[1]
}
return place + "; " + with + "; " + event
when you use a closure with a List and "each", groovy loops over the element in the List, putting the value in the list in the "it" variable. However, since you also want to keep track of the index, there is a groovy eachWithIndex that also passes in the index
http://groovy.codehaus.org/GDK+Extensions+to+Object
so something like
breaks.eachWithIndex {item, index ->
... code here ...
}