So I was able to put data from a file into a table and set the first word of each line a key. How do I display whats in the table in an order based on reading in another file with just the keys?
-- 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.gmatch(line, "%a+") -- word
lines[first_word] = line
end
return lines
end
local lines = lines_from(file)
end
You have some mistakes in your code:
-- see if the file exists
function file_exists(file)
local f = io.open(file, "rb") -- <-- changed "data.txt" to file
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(file) do -- <-- changed "data.txt" to file
first_word = string.match(line, "%a+") -- <-- changed gmatch to match (IMPORTANT)
lines[first_word] = line
end
return lines
end
local lines = lines_from(file)
I removed the last end since it didn't match any block.
The change gmatch to match is critical, since gmatch returns an iterator, a function.
Regarding your question: read the key file, but save its entries in an array manner:
function key_file(file)
if not file_exists(file) then return {} end
keys = {}
for line in io.lines(file) do
key = string.match(line, "%a+")
table.insert(keys, key)
end
return keys
end
In another place you iterate over the key array, using the keys for the lines table:
local lines = lines_from("data.txt")
local keys = key_file("keys.txt")
for i, key in ipairs(keys) do
print(string.format("%d: %s", i, lines[key]))
end
Related
In my Lua project I receive an array, encode it into JSON and pass further. My Lua encode function looks like the following:
local function encode_table(val, stack)
local res = {}
stack = stack or {}
-- Circular reference?
if stack[val] then error("circular reference") end
stack[val] = true
if val[1] ~= nil or next(val) == nil then
-- Treat as array -- check keys are valid and it is not sparse
local n = 0
for k in pairs(val) do
if type(k) ~= "number" then
error("invalid table: mixed or invalid key types")
end
n = n + 1
end
-- need to add a stub somewhere here above the next line
if n ~= #val then
error("invalid table: sparse array") -- THIS TRIGGERS and stops the code
end
-- Encode
for i, v in ipairs(val) do
table.insert(res, encode(v, stack))
end
stack[val] = nil
return "[" .. table.concat(res, ",") .. "]"
else
-- Treat as an object
for k, v in pairs(val) do
if type(k) ~= "string" then
error("invalid table: mixed or invalid key types")
end
table.insert(res, encode(k, stack) .. ":" .. encode(v, stack))
end
stack[val] = nil
return "{" .. table.concat(res, ",") .. "}"
end
end
The problem is that I reveive an array with a 1 element missing. I need to add a stub for it in a key - value manner, say
myArray['missingKey'] = 'somestubvalue'
but I donk know how to do that. Also there is a check in the code for sparse array and this check throws an error, so I need to add a stub before this check is done (pls see the code). Any ideas how to do that would be welcome. Thank you.
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
I'm trying to get the name of all the file saved in two folders, the name are saved as :
1.lua 2.lua 3.lua 4.lua and so on
the folders name are :
first folder : "/const/"
second folder: "/virt/"
what I'm trying to do is only get the number of the files and this works but not in the right order, when I get the 17 file for example I get the 17th delivered from the function before the 15 and this causes for me a problem here the code of the function that I'm using :
local virt_path = "/virt/"
local const_path = "/const"
local fs = require "lfs"
local const = {}
for num = 1, (numberoffile)do -- numberoffile is predfined and can't be change
const[num] = assert(
dofile (const_path .. mkfilename(num)),
"Failed to load constant ".. num ..".")
end
local function file_number() --this is the function that causes me a headach
local ci, co, num = ipairs(const)
local vi, vo, _ = fs.dir(virt_path)
local function vix(o)
local file = vi(o)
if file == nil then return nil end
local number = file:match("^(%d+).lua$")
if number == nil then return vix(o) end
return tonumber(number)
end
local function iter(o, num)
return ci(o.co, num) or vix(o.vo, num)
end
return iter, {co=co, vo=vo}, num
end
As I said the function delive the need return values but not the right Arithmetic order.
any idea what I'm doing wrong here ?
I use my path[1] library.
1 We fill table with filenames
local t = {}
for f in path.each("./*.lua", "n") do
t[#t + 1] = tonumber((path.splitext(f)))
end
table.sort(t)
for _, i in ipairs(t) do
-- do work
end
2 We check if files exists
for i = 1, math.huge do
local p = "./" .. i .. ".lua"
if not path.exists(p) then break end
-- do work
end
[1] https://github.com/moteus/lua-path
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'
I was wondering if there was a way to read data from a file or maybe just to see if it exists and return a true or false
function fileRead(Path,LineNumber)
--..Code...
return Data
end
Try this:
-- http://lua-users.org/wiki/FileInputOutput
-- see if the file exists
function file_exists(file)
local f = io.open(file, "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
local lines = {}
for line in io.lines(file) do
lines[#lines + 1] = line
end
return lines
end
-- tests the functions above
local file = 'test.lua'
local lines = lines_from(file)
-- print all line numbers and their contents
for k,v in pairs(lines) do
print('line[' .. k .. ']', v)
end
You should use the I/O Library where you can find all functions at the io table and then use file:read to get the file content.
local open = io.open
local function read_file(path)
local file = open(path, "rb") -- r read mode and b binary mode
if not file then return nil end
local content = file:read "*a" -- *a or *all reads the whole file
file:close()
return content
end
local fileContent = read_file("foo.html");
print (fileContent);
Just a little addition if one wants to parse a space separated text file line by line.
read_file = function (path)
local file = io.open(path, "rb")
if not file then return nil end
local lines = {}
for line in io.lines(path) do
local words = {}
for word in line:gmatch("%w+") do
table.insert(words, word)
end
table.insert(lines, words)
end
file:close()
return lines;
end
There's a I/O library available, but if it's available depends on your scripting host (assuming you've embedded lua somewhere). It's available, if you're using the command line version. The complete I/O model is most likely what you're looking for.