Related
I am trying to convert existing python function into lua function. But my lua function is not producing same result as python function. Any help is appreciated.
Python function:
import json
test = '{"http://localhost:8080/":{"phone":{"-detail/phone detail.template.html":"5167n,a,7,2","s/motorola-xoom-with-wifi.json":"516a0,5,4,3"},"favicon.ico":"016ad,3,3,2","img/phones/motorola-xoom-with-wi-fi.":{"1.jpg":"*02s,2s,4v,h3|116da,o,l,6","2.jpg":"*02s,2s,4v,kp|116da,j,i,8","3.jpg":"*02s,2s,4v,ob|116da,o,m,8,7,,7,7,7","4.jpg":"*02s,2s,4v,rx|116da,o,m,9,8,,7,7,7","5.jpg":"*02s,2s,4v,vj|116da,p,m,a,8,,7,7,7"}}}'
def tri(param):
t = {}
for key in param:
if key not in param:
continue
if isinstance(param[key], dict) and param[key] is not None:
flat = tri(param[key])
for x in flat:
if x not in flat:
continue
t[key + x] = flat[x]
else:
t[key] = param[key]
return t
print(tri(json.loads(test)))
Lua code ( which is not producing same result as python function)
local json = require('cjson')
local test = '{"http://localhost:8080/":{"phone":{"-detail/phone-detail.template.html":"5167n,a,7,2","s/motorola-xoom-with-wi-fi.json":"516a0,5,4,3"},"favicon.ico":"016ad,3,3,2","img/phones/motorola-xoom-with-wi-fi.":{"1.jpg":"*02s,2s,4v,h3|116da,o,l,6","2.jpg":"*02s,2s,4v,kp|116da,j,i,8","3.jpg":"*02s,2s,4v,ob|116da,o,m,8,7,,7,7,7","4.jpg":"*02s,2s,4v,rx|116da,o,m,9,8,,7,7,7","5.jpg":"*02s,2s,4v,vj|116da,p,m,a,8,,7,7,7"}}}'
local function tri(param)
t = {}
for key in pairs(param) do
if param[key] == nil then end
if type(param[key]) == "table" then
flat = tri(param[key])
for k in pairs(flat) do
t[key .. k] = flat[k]
end
else
t[key] = param[key]
end
end
return t
end
print(json.encode(tri(json.decode(test))))
local function tri(param)
t = {} -- every time we call tri t will be "reset" to an empty table
for key in pairs(param) do
if param[key] == nil then end
if type(param[key]) == "table" then
flat = tri(param[key]) -- here we call tri, but we still need t!
for k in pairs(flat) do
t[key .. k] = flat[k]
end
else
t[key] = param[key]
end
end
return t
end
Making at least t global should solve that problem. But there is also no reason for flat to be global so we make it local too.
local function tri(param)
local t = {}
for key in pairs(param) do
if param[key] == nil then end
if type(param[key]) == "table" then
local flat = tri(param[key])
for k in pairs(flat) do
t[key .. k] = flat[k]
end
else
t[key] = param[key]
end
end
return t
end
Your task could be done a bit easier using json.traverse() function from this Lua JSON module.
Traversing lets you perform arbitrary operations with JSON elements on-the-fly.
This code concatenates element's path (for every JSON element except JSON containers: arrays/objects) and uses it as a key for Lua table.
local json = require'json'
local t = {}
local function callback(path, json_type, value)
if value ~= nil then -- value == nil for containers (arrays/objects)
t[table.concat(path)] = value
end
end
local test = '{"http://localhost:8080/":{"phone":{"-detail/phone detail.template.html":"5167n,a,7,2","s/motorola-xoom-with-wifi.json":"516a0,5,4,3"},"favicon.ico":"016ad,3,3,2","img/phones/motorola-xoom-with-wi-fi.":{"1.jpg":"*02s,2s,4v,h3|116da,o,l,6","2.jpg":"*02s,2s,4v,kp|116da,j,i,8","3.jpg":"*02s,2s,4v,ob|116da,o,m,8,7,,7,7,7","4.jpg":"*02s,2s,4v,rx|116da,o,m,9,8,,7,7,7","5.jpg":"*02s,2s,4v,vj|116da,p,m,a,8,,7,7,7"}}}'
json.traverse(test, callback)
-- Now t == {
-- ["http://localhost:8080/favicon.ico"] = "016ad,3,3,2",
-- ["http://localhost:8080/img/phones/motorola-xoom-with-wi-fi.1.jpg"] = "*02s,2s,4v,h3|116da,o,l,6",
-- ["http://localhost:8080/img/phones/motorola-xoom-with-wi-fi.2.jpg"] = "*02s,2s,4v,kp|116da,j,i,8",
-- ["http://localhost:8080/img/phones/motorola-xoom-with-wi-fi.3.jpg"] = "*02s,2s,4v,ob|116da,o,m,8,7,,7,7,7",
-- ["http://localhost:8080/img/phones/motorola-xoom-with-wi-fi.4.jpg"] = "*02s,2s,4v,rx|116da,o,m,9,8,,7,7,7",
-- ["http://localhost:8080/img/phones/motorola-xoom-with-wi-fi.5.jpg"] = "*02s,2s,4v,vj|116da,p,m,a,8,,7,7,7",
-- ["http://localhost:8080/phone-detail/phone detail.template.html"] = "5167n,a,7,2",
-- ["http://localhost:8080/phones/motorola-xoom-with-wifi.json"] = "516a0,5,4,3"
-- }
I figured out the main concept of my code which reads in a file and sets it to a key then reads in another file and displays the info based on that file. How do I add line 1, line 2. line 3 and so on in front of the output? As well as add ------------ above and below each new line.
-- see if the file exists
function file_exists(file)
local f = io.open("data.txt", "rb")
if f then f:close() end
return f ~= nil
end
-- get all lines from a file, returns an empty
-- list/table if the file does not exist
function lines_from(file)
if not file_exists(file) then return {} end
lines = {}
for line in io.lines("data.txt") do
first_word = string.match(line, "%a+") -- word
lines[first_word] = line
lines[#lines + 1] = lin
end
return lines
end
local lines = lines_from(file)
function key_file(file)
if not file_exists(file) then return {} end
keys = {}
for line in io.lines("keys.txt") do
key = string.match(line, "%a+")
table.insert(keys, key)
end
return keys
end
local lines = lines_from("data.txt")
local keys = key_file("keys.txt")
for _, key in ipairs(keys) do
print(lines[key])
end
I'll answer this in a more general way as your code is not working atm.
You can simply add print commands in the for loop that prints the lines. Or you alter the texts by in some way. See Lua reference documentation for string manipulation and concat operator ..
local numLine = 0
for _, key in pairs(keys) do
numLine = numLine + 1
print("Line " .. numLine .. ": " .. lines[key])
print("----------")
end
Assuming I have a piece of code such as the following
aTable = {aValue=1}
aTable_mt = {}
print(aTable)
What must I do to make Lua print something like aTable current aValue = 1 as opposed to table: 0x01ab1d2.
So far I've tried setting the __tostring metamethod but that doesn't seem to be invoked by print. Is there some metamethod I've been missing or does the answer have nothing to do with metamethods?
__tostring works:
aTable = {aValue=1}
local mt = {__tostring = function(t)
local result = ''
for k, v in pairs(t) do
result = result .. tostring(k) .. ' ' .. tostring(v) .. ''
end
return result
end}
setmetatable(aTable, mt)
print(aTable)
This prints aValue 1 (with one extra whitespace, remove it in real code). The aTable part is not available, because aTable is a variable that references the table, not the content of the table itself.
I'm not sure how you set the metamethod, but the following code prints "stringified" for me:
local aTable = {a = 1, b = 2}
setmetatable(aTable, {__tostring = function() return "stringified" end})
print(aTable)
If you want lua to generally print all tables human readable, you could
hook up/overwrite the print function:
local orig_print = print
print = function(...)
local args = {...}
for i,arg in ipairs(args) do
if type(arg) == 'table' then
args[i] = serialize(arg)
end
end
orig_print(table.unpack(args))
end
serialize could be serpent or some other lib from here
Note that this must be done before any other module/script is loaded.
I would like to learn by developing a help function. The code below outlines my plan, and it can be summarized as:
For functions defined in Lua files - look for comments in the source.
For built-in functions and DLLs - look for a text file in .\help\function.txt.
For libraries (if no comments in the source) - look for a text file in .\lib\help\function.txt.
At the end of my code you can see an attempt to build an index of function names using their unique tostring(function) return value. Surely I should be able to do this in a loop?
function learn()
-- learn()
-- Make it easier to learn Lua, based upon Matlab console functions
-- help() print for help text in function source or help directory
-- who() print defined variables (exlcuding those in loaded modules)
-- what() print defined functions (exlcuding those in loaded modules)
-- which() print path to function source file if present
-- list() print the file to the console
-- edit() edit "filename" or function source if present
-- note: edit(_) can be used after any call to list(), help(func),
-- Helper functions
-- table.name() returns table name as string
-- table.length() this is difficult
-- table.keylist() returns a list of keys
-- table.keytype() returns a list of key types
-- edit_source() process function names
-- edit_new() create new "filename" (will use but not make subdirectories)
-- string.split() returns a table from a string
-- io.exists() test if a filename exists
-- io.newfile() creates an empty file
--
-- global variables
-- editor = "P:\\MyPrograms\\EDITORS\\Addins\\Editor2\\editor2.exe "
-- helpindex a list of the names of the inbuilt functions - see end of file
-- topics a table of help topics see topics.lua
-- web = "web"
web = "web"
-- webhelp = "http://www.nongnu.org/gsl-shell/doc/"
webhelp = "http://www.nongnu.org/gsl-shell/doc/"
-- editor = "P:\\MyPrograms\\EDITORS\\Addins\\Editor2\\editor2.exe "
editor = "P:\\MyPrograms\\EDITORS\\Addins\\Editor2\\editor2.exe "
-- required packages
-- lfs - lua file system (binary from lua-files)
require("lfs")
-- topics - for the help system
require("topics")
end
learn()
function who(t,i)
-- who(table)
-- searches the table (or defaults to _G) to print a list of table keys + types
-- the second parameter is to add a prefix for a recursive call to search "sub" tables
-- still having difficulty with the "loaded" table as this is self referencing and sets up an infinate loop!
-- designed for the console, but could be modified to return a table
--
if type(t)~="table" then
t=_G
end
if type(i)~="string" then
i=""
end
local s={}
local u={}
s = table.keylist(t)
u = table.keytype(t)
for k,v in ipairs(s) do
if u[k]=="table" and s[k]~="_G" and s[k]~="loaded" then
who(t[s[k]],i..v..".")
else
if u[k]~="table" and u[k]~="function" and u[k]~="cdata" then
print(u[k], i..v)
end
end
end
end
function what(t,i)
-- what(table)
-- searches the table (or defaults to _G) to print a list of function names
-- the second parameter is to add a prefix for a recursive call to search "sub" tables
-- still having difficulty with the "loaded" table as this is self referencing and sets up an infinate loop!
-- designed for the console, but could be modified to return a table
--
if type(t)~="table" then
t=_G
end
if type(i)~="string" then
i=""
end
local s={}
local u={}
s = table.keylist(t)
u = table.keytype(t)
for k,v in ipairs(s) do
if u[k]=="table" and s[k]~="_G" and s[k]~="loaded" then
what(t[s[k]],i..v..".")
else
if u[k]=="function" then
print(u[k], i..v)
end
end
end
end
function which(funcname)
-- which(funcname)
-- identifies the source for the current definition of funcname
-- designed for the console, but could be modified to return a string
--
if type(funcname)~="function" then return end
local filename = _G.debug.getinfo(funcname).short_src
if filename=="[C]" then
print(tostring(funcname))
else
return filename
end
end
function help(funcname)
-- help(object)
-- for functions prints help text (from source or help\function.txt)
-- adding help text to source as ^--comments is recommended,
-- for builtin functions use a subdirectory from the executable,
-- for uncommented source add a sibling help directory
-- for table prints table name, size and list of contents
-- for variables prints the type of the object
--
if type(funcname)=="boolean" then
io.write("boolean: ")
print(funcname)
return
end
if type(funcname)=="string" then
if funcname=="web" then
os.launch(webhelp)
else
print("string: "..funcname)
end
return
end
if type(funcname)=="number" then
print("number: "..funcname)
return
end
if type(funcname) == 'userdata' then
print(tostring(funcname))
io.write("metadata: ")
print(getmetatable(funcname))
end
if type(funcname) == 'cdata' then
print(tostring(funcname))
-- *** Unfinished
end
if type(funcname)=="table" then
print(tostring(funcname)..", size: "..table.length(funcname))
who(funcname)
what(funcname)
return
end
if type(funcname)=="function" then
-- Test for a source file
local filename = _G.debug.getinfo(funcname).short_src
if io.exists(filename) then
local codestart = _G.debug.getinfo(funcname).linedefined
local codeend = _G.debug.getinfo(funcname).lastlinedefined
if codestart < 1 then
print("Start is less than 1")
codestart = 1
end
if codeend< 1 then
print("End is less than 1")
codeend= 100
end
-- Try to read comments from the source
local output = 0
local count = 0
for line in io.lines(filename) do
count = count+1
if count > codestart and count < codeend then
if line:match("^%-%-") then
print(line)
output = output + 1
end
end
end
if output>0 then
io.write("From : ")
return filename -- to be used with edit(_)
end
-- Test for a help file as a sibling of the source
if output==0 then
-- No comments in the source file so look for a help file
local t = string.split(filename, "\\")
local helppath = table.concat(t,"\\",1,table.length(t)-1).."\\help\\"..t[table.length(t)]
helppath = string.gsub(helppath, "%.lua$" , ".txt")
if io.exists(helppath) then
local filename = list(helppath)
io.write("From : ")
return filename -- to be used with edit(_)
else
print("No help in source file : "..filename)
io.write("No help in: ")
return helppath -- to be used with edit_new(_)
end
end
end
-- Test for a help file in the generic help directory
if helpindex[tostring(funcname)] then
local helppath = "help\\"..helpindex[tostring(funcname)]..".txt"
if io.exists(helppath) then
local filename = list(helppath)
io.write("From : ")
return filename -- to be used with edit(_)
else
io.write("Built in function, but no help in: ")
return helppath -- to be used with edit_new(_)
end
else
print("No help index entry for "..tostring(funcname))
return
end
end
end
function list(filename)
if type(filename)=="function" then
print("list will only accept a string with a valid file name")
return
end
if type(filename)~="string" then
print("list will only accept a string with a valid file name")
return
end
if io.exists(filename) then
for line in io.lines(filename) do
print(line)
end
return filename
else
io.write("Can't find file: ")
return filename
end
end
function edit(filename, linenum)
-- edit(filename[, linenum])
-- loads the file into my editor (defined as global editor)
-- the linenum parameter will move the cursor to linenum
-- you will need to edit the global "editor" and the source command line below
-- or download EditorĀ² from http://www.zabkat.com
--
if type(filename)=="function" then
filename = edit_source(filename)
return filename
end
if type(filename)~="string" then return end
if type(linenum)~="number" then linenum=1 end
if io.exists(filename) then
os.launch(editor.." /P /L:"..linenum.." \""..filename.."\"", " /P /L:"..linenum.." \""..filename.."\"")
else
print("To make a new file edit_new('filename')")
io.write("Can't find file: ")
return filename
end
end
function edit_source(funcname)
if type(funcname)~="function" then return end
local filename = _G.debug.getinfo(funcname).short_src
if io.exists(filename) then
local linenum = _G.debug.getinfo(funcname).linedefined
if linenum < 1 then
linenum = 1
end
edit(filename, linenum)
io.write("Editing : ")
return filename
end
end
function edit_new(filename)
if type(filename)~="string" then return end
io.newfile(filename)
edit(filename) -- This will check for a valid file name
io.write("Editing : ")
return filename
end
function table.name(table)
if type(table)~="table" then return end
for k, v in pairs(_G) do
if v == table then
return k
end
end
return nil
end
function table.length(table)
if type(table)~="table" then return end
local len = 0
for _ in pairs(table) do
len = len + 1
end
if type(len)=="number" then
return len
else
return nil
end
end
function table.keylist(table)
if type(table)~="table" then return end
local keylist={}
local n=0
for key in pairs(table) do
n=n+1
keylist[n]=key
end
return keylist
end
function table.keytype(table)
if type(table)~="table" then return end
local keytype={}
local n=0
for key in pairs(table) do
n=n+1
keytype[n]=type(table[key])
end
return keytype
end
function table.tablelist(table)
if type(table)~="table" then return end
local tablelist={}
local n=0
for key in pairs(table) do
if type(table[key])=="table" then
n=n+1
tablelist[n]=key
end
end
return tablelist
end
function string.split(inputstr, sep)
if sep == nil then
sep = "%s"
end
local t={}
local i=1
for str in string.gmatch(inputstr, "([^"..sep.."]+)") do
t[i] = str
i = i + 1
end
return t
end
function io.newfile(filename)
-- io.newfile(filename)
-- Will create a file if this is a valid filename
-- relative paths will work
-- files will not be overwritten
if type(filename)~="string" then
print("This function requires a string")
return
end
if io.exists(filename) then
io.write("This file already exists : ")
return filename
end
file, errormsg = io.open(filename, "w")
if errormsg then
print(errormsg)
else
file:write()
file:close()
io.write("New file created : ")
return filename
end
end
function io.exists(filename)
if type(filename)~="string" then return false end
local f=io.open(filename,"r")
if f~=nil then
io.close(f) return true
else
return false
end
end
function os.launch(command,params)
-- Via a dos box works - but flashes up a dos console
-- would love a way round this problem
command = "start "..command
os.execute(command)
end
helpindex = {
[tostring(assert)] = "assert",
[tostring(collectgarbage)] = "collectgarbage",
[tostring(dofile)] = "dofile",
[tostring(error)] = "error",
[tostring(getfenv)] = "getfenv",
[tostring(getmetatable)] = "getmetatable",
[tostring(ipairs)] = "ipairs",
[tostring(load)] = "load",
[tostring(loadfile)] = "loadfile",
[tostring(loadstring)] = "loadstring",
[tostring(next)] = "next" ,
[tostring(pairs)] = "pairs" ,
[tostring(pcall)] = "pcall" ,
[tostring(rawequal)] = "rawequal" ,
[tostring(rawget)] = "rawget" ,
[tostring(rawset)] = "rawset" ,
[tostring(select)] = "select" ,
[tostring(setfenv)] = "setfenv" ,
[tostring(setmetatable)] = "setmetatable" ,
[tostring(tonumber)] = "tonumber" ,
[tostring(tostring)] = "tostring" ,
[tostring(type)] = "type" ,
[tostring(unpack)] = "unpack" ,
[tostring(xpcall)] = "xpcall" ,
[tostring(coroutine.create)] = "coroutine.create" ,
[tostring(coroutine.resume)] = "coroutine.resume" ,
[tostring(coroutine.running)] = "coroutine.running" ,
[tostring(coroutine.status )] = "coroutine.status ",
[tostring(coroutine.wrap)] = "coroutine.wrap" ,
[tostring(coroutine.yield)] = "coroutine.yield" ,
[tostring(string.byte)] = "string.byte" ,
[tostring(string.char)] = "string.char" ,
[tostring(string.dump)] = "string.dump" ,
[tostring(string.find )] = "string.find",
[tostring(string.format)] = "string.format" ,
[tostring(string.gmatch)] = "string.gmatch" ,
[tostring(string.gsub)] = "string.gsub" ,
[tostring(string.len)] = "string.len" ,
[tostring(string.lower)] = "string.lower" ,
[tostring(string.match)] = "string.match" ,
[tostring(string.rep)] = "string.rep" ,
[tostring(string.reverse)] = "string.reverse" ,
[tostring(string.sub)] = "string.sub" ,
[tostring(string.upper)] = "string.upper" ,
[tostring(table.concat)] = "table.concat" ,
[tostring(table.insert)] = "table.insert" ,
[tostring(table.maxn)] = "table.maxn" ,
[tostring(table.remove)] = "table.remove" ,
[tostring(table.sort)] = "table.sort" ,
[tostring(math.abs)] = "math.abs" ,
[tostring(math.acos)] = "math.acos" ,
[tostring(math.asin)] = "math.asin" ,
[tostring(math.atan)] = "math.atan" ,
[tostring(math.atan2)] = "math.atan2" ,
[tostring(math.ceil)] = "math.ceil" ,
[tostring(math.cos)] = "math.cos" ,
[tostring(math.cosh)] = "math.cosh" ,
[tostring(math.deg)] = "math.deg" ,
[tostring(math.exp)] = "math.exp" ,
[tostring(math.floor)] = "math.floor" ,
[tostring(math.fmod)] = "math.fmod" ,
[tostring(math.frexp)] = "math.frexp" ,
[tostring(math.ldexp)] = "math.ldexp" ,
[tostring(math.log)] = "math.log" ,
[tostring(math.log10)] = "math.log10" ,
[tostring(math.max)] = "math.max" ,
[tostring(math.min)] = "math.min" ,
[tostring(math.modf)] = "math.modf" ,
[tostring(math.pow)] = "math.pow" ,
[tostring(math.rad)] = "math.rad" ,
[tostring(math.random)] = "math.random" ,
[tostring(math.randomseed)] = "math.randomseed" ,
[tostring(math.sin)] = "math.sin" ,
[tostring(math.sinh)] = "math.sinh" ,
[tostring(math.sqrt)] = "math.sqrt" ,
[tostring(math.tan)] = "math.tan" ,
[tostring(math.tanh)] = "math.tanh" ,
[tostring(io.close)] = "io.close" ,
[tostring(io.flush)] = "io.flush" ,
[tostring(io.input)] = "io.input" ,
[tostring(io.lines)] = "io.lines" ,
[tostring(io.open)] = "io.open" ,
[tostring(io.output)] = "io.output" ,
[tostring(io.popen)] = "io.popen" ,
[tostring(io.read)] = "io.read" ,
[tostring(io.tmpfile)] = "io.tmpfile" ,
[tostring(io.type)] = "io.type" ,
[tostring(io.write)] = "io.write" ,
[tostring(os.clock)] = "os.clock" ,
[tostring(os.date)] = "os.date" ,
[tostring(os.difftime)] = "os.difftime" ,
[tostring(os.execute)] = "os.execute" ,
[tostring(os.exit)] = "os.exit" ,
[tostring(os.getenv)] = "os.getenv" ,
[tostring(os.remove)] = "os.remove" ,
[tostring(os.rename)] = "os.rename" ,
[tostring(os.setlocale)] = "os.setlocale" ,
[tostring(os.time)] = "os.time" ,
[tostring(os.tmpname)] = "os.tmpname" ,
[tostring(debug.debug)] = "debug.debug" ,
[tostring(debug.getfenv)] = "debug.getfenv" ,
[tostring(debug.gethook)] = "debug.gethook" ,
[tostring(debug.getinfo)] = "debug.getinfo" ,
[tostring(debug.getlocal)] = "debug.getlocal" ,
[tostring(debug.getmetatable)] = "debug.getmetatable" ,
[tostring(debug.getregistry)] = "debug.getregistry" ,
[tostring(debug.getupvalue)] = "debug.getupvalue" ,
[tostring(debug.setfenv)] = "debug.setfenv" ,
[tostring(debug.sethook)] = "debug.sethook" ,
[tostring(debug.setlocal)] = "debug.setlocal" ,
[tostring(debug.setmetatable)] = "debug.setmetatable" ,
[tostring(debug.setupvalue)] = "debug.setupvalue" ,
[tostring(debug.traceback)] = "debug.traceback" ,
[tostring(module)] = "module" ,
[tostring(package.loadlib)] = "package.loadlib" ,
[tostring(package.seeall)] = "package.seeall" ,
[tostring(print)] = "print" ,
[tostring(require)] = "require" ,
[tostring(graph.fxplot)] = "graph.fxplot"
}
Revised code:
function help(funcname)
-- help(object)
-- for functions prints help text (from source or help\function.txt)
-- adding help text to source as ^--comments is recommended,
-- for builtin functions use a subdirectory from the executable,
-- for uncommented source add a sibling \help directory and function.txt
-- (note that the source file may contain several functions)
-- for table prints table name, size and list of contents
-- for variables prints the type of the object
--
if type(funcname)=="boolean" then
io.write("boolean: ")
print(funcname)
return
end
if type(funcname)=="string" then
if funcname=="web" then
os.launch(webhelp)
else
print("string: "..funcname)
end
return
end
if type(funcname)=="number" then
print("number: "..funcname)
return
end
if type(funcname) == 'userdata' then
print(tostring(funcname))
io.write("metadata: ")
print(getmetatable(funcname))
end
if type(funcname) == 'cdata' then
print(tostring(funcname))
-- *** Unfinished
end
if type(funcname)=="table" then
print(tostring(funcname)..", size: "..table.length(funcname))
who(funcname)
what(funcname)
return
end
if type(funcname)=="function" then
-- Test for a source file
local filename = _G.debug.getinfo(funcname).short_src
if io.exists(filename) then
local codestart = _G.debug.getinfo(funcname).linedefined
local codeend = _G.debug.getinfo(funcname).lastlinedefined
if codestart < 1 then
print("Start is less than 1")
codestart = 1
end
if codeend< 1 then
print("End is less than 1")
codeend= 100
end
-- Try to read comments from the source
local output = 0
local count = 0
for line in io.lines(filename) do
count = count+1
if count > codestart and count < codeend then
if line:match("^%-%-") then
print(line)
output = output + 1
end
end
end
if output>0 then
io.write("From : ")
return filename -- to be used with edit(_)
end
-- Try to read comments from \help\function.txt
if output==0 then
-- No comments in the source file so look for a help file
local t = string.split(filename, "\\")
local helppath = table.concat(t,"\\",1,table.length(t)-1).."\\help\\"..helpindex[funcname]..".txt"
if io.exists(helppath) then
local filename = list(helppath)
io.write("From : ")
return filename -- to be used with edit(_)
else
print("No help in source file : "..filename)
io.write("No help in: ")
return helppath -- to be used with edit_new(_)
end
end
end
-- Test for a help file in the generic help directory
if helpindex[funcname] then
local helppath = "help\\"..helpindex[funcname]..".txt"
if io.exists(helppath) then
local filename = list(helppath)
io.write("From : ")
return filename -- to be used with edit(_)
else
io.write("Built in function, but no help in: ")
return helppath -- to be used with edit_new(_)
end
else
print("No help index entry for "..helpindex[funcname])
return
end
end
end
-- helpindex as a [function literal -> string] mapping of names.
-- many thanks to Ryan Stein
-- http://stackoverflow.com/questions/20269173/lua-help-function-can-i-extract-the-name-of-a-function
helpindex = {}
do
local function indexfn(t, n)
if n == '_G' then n = '' else n = n .. '.' end
for k, v in pairs(t) do
if type(v) == 'function' then
helpindex[v] = n .. k
end
end
end
for k, v in pairs(_G) do -- Iterate all tables in global scope.
if type(v) == 'table' then
indexfn(v, k)
end
end
end
Perhaps this may be what you're looking for:
local helpindex = {}
do
local function indexfn(t, n)
if n == '_G' then n = '' else n = n .. '.' end
for k, v in pairs(t) do
if type(v) == 'function' then
helpindex[v] = n .. k
end
end
end
for k, v in pairs(_G) do -- Iterate all tables in global scope.
if type(v) == 'table' then
indexfn(v, k)
end
end
end
-- helpindex is now a [function literal -> string] mapping of names.
You don't need to convert the functions to strings to use them as table keys, since anything other than nil can be used as a table key in Lua. The functions themselves work just fine.
I have 2 functions in Lua which create a dictionary table and allow to check if a word exists:
local dictTable = {}
local dictTableSize = 0
function buildDictionary()
local path = system.pathForFile("wordlist.txt")
local file = io.open( path, "r")
if file then
for line in file:lines() do
dictTable[line] = true
dictTableSize = dictTableSize + 1
end
io.close(file)
end
end
function checkWord(word)
if dictTable[word] then
return(true)
else
return(false)
end
end
Now I want to be able to generate a couple of random words. But since the words are the keys, how can I pick some, given the dictTableSize.
Thanks
Just add a numerical index for each word to the dictionary while loading it:
function buildDictionary()
local path = system.pathForFile("wordlist.txt")
local file = io.open( path, "r")
if file then
local index = 1
for line in file:lines() do
dictTable[line] = true
dictTable[index] = line
index = index + 1
end
io.close(file)
end
end
Now you can get a random word like this:
function randomWord()
return dictTable[math.random(1,#dictTable)]
end
Side note: nil evaluates to false in Lua conditionals, so you could write checkWord like this:
function checkWord(word)
return dictTable[word]
end
Another side note, you'll get less polution of the global namespace if you wrap the dictionary functionality into an object:
local dictionary = { words = {} }
function dictionary:load()
local path = system.pathForFile('wordlist.txt')
local file = io.open( path, 'r')
if file then
local index = 1
for line in file:lines() do
self.words[line] = true
self.words[index] = line
index = index + 1
end
io.close(file)
end
end
function dictionary:checkWord(word)
return self.words[word]
end
function dictionary:randomWord()
return self.words[math.random(1,#self.words)]
end
Then you can say:
dictionary:load()
dictionary:checkWord('foobar')
dictionary:randomWord()
Probably two ways: you can keep the array with words and just do words[math.random(#words)] when you need to pick a random word (just make sure that the second one is different from the first).
The other way is to use next the number of times you need:
function findNth(t, n)
local val = next(t)
for i = 2, n do val = next(t, val) end
return val
end
This will return b for findNth({a = true, b = true, c = true}, 3) (the order is undefined).
You can avoid repetitive scanning by memoizing the results (at this point you will be better off using the first way).
this is a trade off that you have for using the word table the way you are. i would invert the word table once you load it, so that you can get references to words by index as well if you have to. something like this:
-- mimic your dictionary structure
local t = {
["asdf"] = true, ["wer"] = true, ["iweir"] = true, ["erer"] = true
}
-- function to invert your word table
function invert(tbl)
local t = {}
for k,_ in pairs(tbl) do
table.insert(t, k)
end
return t
end
-- now the code to grab random words
local idx1, idx2 = math.random(dictTableSize), math.random(dictTableSize)
local new_t = invert(t)
local word1, word2 = new_t[idx1], new_t[idx2]
-- word1 and word2 now have random words from your 'dictTable'