What does [{n,{}}] do in lua? - lua

As you can tell I'm a beginner in lua. I am trying to understand a function I'm stuck at what the following code segment does?
It is used in the following code snippet in the last line:
function classify(txt_dir, img_dir, cls_list)
local acc = 0.0
local total = 0.0
local fea_img = {}
local fea_txt = {}
for fname in io.lines(cls_list) do
local imgpath = img_dir .. '/' .. fname .. '.t7'
local txtpath = txt_dir .. '/' .. fname .. '.t7'
fea_img[#fea_img + 1] = extract_img(imgpath)
fea_txt[#fea_txt + 1] = extract_txt(txtpath)
end
for i = 1,#fea_img do
-- loop over individual images.
for k = 1,fea_img[i]:size(1) do
local best_match = 1
local best_score = -math.huge
for j = 1,#fea_txt do
local cur_score = torch.dot(fea_img[i][{k,{}}], fea_txt[j])
From my understanding, fea_img is a lua table. Is the line fea_img[i][{k,{}}] some sort of slicing for the value for the key 'i' in the table fea_img?
I tried searching for more examples and found this being used here too (last line):
for i = 1,nsamples,batchsize do
-- indices
local lasti = math.min(i+batchsize-1,nsamples)
local m = lasti - i + 1
-- k-means step, on minibatch
local batch = x[{ {i,lasti},{} }]
Any help on this would be really appreciated. Thank you!

In lua you can access a specific index on a table in multiple ways. Like these two examples
local myValue = someTable.theIndex
-- or
local myOtherValue = someTable[2]
So the construct you see here is to access some values from a (nested) table.
Also in lua you can use anything except nil as a index, so even tables are possible.
The line
fea_img[i][{k,{}}]
Can be extended to this:
local index1 = i -- i in this case is your loop variable
local index2 = { k , { } } -- This creates a table with 2 values, the first one will be the vaule of the var k, the second one is an empty table
local value1 = fea_img[index1] -- This will get you a table
local value2 = value1[index2] -- This will get the same as: fea_img[i][{k,{}}]
Correction and Addition:
As Nicol Bolas already said in the comments: The index must be an exact match. Which means it literally has to be the same table, which is not the case for the presented code from you. Either you dropped code you thought is unnecessary or fea_img has some some kind of metatable on it.
In the case of
local k = 2
local table1 = {k, { } }
local table2 = {k, { } }
table2 and table1 do have the exact same content. But they are not the same table. Which will lead to nil always being retrieved if one is used to store data in a table and the other is used to get it back.

Syntactically, t[k] is indexing a table with a key. Normally, if there is a record in the table with the key k, its value is returned. Nothing more, nothing less.
If fea_img[i] was a normal table, {k,{}} would always return nil, since table indices are resolved based on their identity ({k,{}} is always a new table). Based on your code, I have to conclude that the elements of fea_img (i.e. what extract_img returns) are not normal tables.
In Lua, you can override the indexing operation using a metatable. If you index a value that has a metatable with __index, it will be used if there is no matching record in the table:
local t = {}
setmetatable(t, {
__index = function(t, k)
return k
end
})
print(t[{}])
This table has a metatable associated with it, which is used in the indexing operation. In this case __index returns the key, but whatever library you are using might provide more complex behaviour.
This is specific to the library you are using, not something related to the Lua syntax.

Related

save strings in lua table

Does someone know a solution to save the key and the values to an table? My idea does not work because the length of the table is 0 and it should be 3.
local newstr = "3 = Hello, 67 = Hi, 2 = Bye"
a = {}
for k,v in newstr:gmatch "(%d+)%s*=%s*(%a+)" do
--print(k,v)
a[k] = v
end
print(#a)
The output is correct.
run for k,v in pairs(a) do print(k,v) end to check the contents of your table.
The problem is the length operator which by default cannot be used to get the number of elements of any table but a sequence.
Please refer to the Lua manual: https://www.lua.org/manual/5.4/manual.html#3.4.7
When t is a sequence, #t returns its only border, which corresponds to
the intuitive notion of the length of the sequence. When t is not a
sequence, #t can return any of its borders. (The exact one depends on
details of the internal representation of the table, which in turn can
depend on how the table was populated and the memory addresses of its
non-numeric keys.)
Only use the length operator if you know t is a sequence. That's a Lua table with integer indexes 1,..n without any gap.
You don't have a sequence as you're using non-numeric keys only. That's why #a is 0
The only safe way to get the number of elements of any table is to count them.
local count = 0
for i,v in pairs(a) do
count = count + 1
end
You can put #Piglet' code in the metatable of a as method __len that is used for table key counting with length operator #.
local newstr = "3 = Hello, 67 = Hi, 2 = Bye"
local a = setmetatable({},{__len = function(tab)
local count = 0
for i, v in pairs(tab) do
count = count + 1
end
return count
end})
for k,v in newstr:gmatch "(%d+)%s*=%s*(%a+)" do
--print(k,v)
a[k] = v
end
print(#a) -- puts out: 3
The output of #a with method __len even is correct if the table holds only a sequence.
You can check this online in the Lua Sandbox...
...with copy and paste.
Like i do.

LUA: Looking for a specific table by its variable

I'm currently starting work on a text adventure game in Lua--no addons, just pure Lua for my first project. In essence, here is my problem; I'm trying to find out how I can do a "reverse lookup" of a table using one of its variables. Here's an example of what I've tried to do:
print("What are you trying to take?")
bag = {}
gold = {name="Gold",ap=3}
x = io.read("*l")
if x == "Gold" then
table.insert(bag,gold)
print("You took the " .. gold.name .. ".")
end
Obviously, writing a line like this with every single object in the game would be very... exhausting--especially since I think I'll be able to use this solution for not just taking items but movement from room to room using a reverse lookup with each room's (x,y) coordinates. Anyone have any ideas on how to make a more flexible system that can find a table by the player typing in one of its variables? Thanks in advance!
-blockchainporter
This doesn't directly answer your question as you asked it, but I think it would serve the purpose of what you are trying to do. I create a table called 'loot' which can hold many objects, and the player can place any of these in their 'bag' by typing the name.
bag = {}
loot = {
{name="Gold", qty=3},
{name="Axe", qty=1},
}
print("What are you trying to take?")
x = io.read("*l")
i = 1
while loot[i] do
if (x == loot[i].name) then
table.insert(bag, table.remove(loot,i))
else
i = i + 1
end
end
For bonus points, you could check 'bag' to see if the player has some of that item already and then just update the quantity...
while loot[i] do
if (x == loot[i].name) then
j, found = 1, nil
while bag[j] do
if (x == bag[j].name) then
found = true
bag[j].qty = bag[j].qty + loot[i].qty
table.remove(loot,i)
end
j = j + 1
end
if (not found) then
table.insert(bag, table.remove(loot,i))
end
else
i = i + 1
end
end
Again, this isn't a 'reverse lookup' solution like you asked for... but I think it is closer to what you are trying to do by letting a user choose to loot something.
My disclaimer is that I don't use IO functions in my own lua usage, so I have to assume that your x = io.read("*l") is correct.
PS. If you only ever want objects to have a name and qty, and never any other properties (like condition, enchantment, or whatever) then you could also simplify my solution by using key/val pairs:
bag = {}
loot = { ["Gold"] = 3, ["Axe"] = 1 }
print("What are you trying to take?")
x = io.read("*l")
for name, qty in pairs(loot) do
if x == name then
bag.name = (bag.name or 0) + qty
loot.name = nil
end
end
I have a few notes to start before I specifically address your question. (I just want to do this before I forget, so please bear with me!)
I recommend printing to the terminal using stderr instead of stdout--the Lua function print uses the latter. When I am writing a Lua script, I often create a C-style function called eprintf to print formatted output to stderr. I implement it like this:
local function eprintf(fmt, ...)
io.stderr:write(string.format(fmt, ...))
return
end
Just be aware that, unlike print, this function does not automatically append a newline character to the output string; to do so, remember to put \n at the end of your fmt string.
Next, it may be useful to define a helper function that calls io.read("*l") to get an entire line of input. In writing some example code to help answer your question, I called my function getline--like the C++ function that has similar behavior--and defined it like this:
local function getline()
local read = tostring(io.read("*l"))
return read
end
If I correctly understand what it is you are trying to do, the player will have an inventory--which you have called bag--and he can put items into it by entering item names into stdin. So, for instance, if the player found a treasure chest with gold, a sword, and a potion in it and he wanted to take the gold, he would type Gold into stdin and it would be placed in his inventory.
Based on what you have so far, it looks like you are using Lua tables to create these items: each table has a name index and another called ap; and, if a player's text input matches an item's name, the player picks that up item.
I would recommend creating an Item class, which you could abstract nicely by placing it in its own script and then loading it as needed with require. This is a very basic Item class module I wrote:
----------------
-- Item class --
----------------
local Item = {__name = "Item"}
Item.__metatable = "metatable"
Item.__index = Item
-- __newindex metamethod.
function Item.__newindex(self, k, v)
local err = string.format(
"type `Item` does not have member `%s`",
tostring(k)
)
return error(err, 2)
end
-- Item constructor
function Item.new(name_in, ap_in)
assert((name_in ~= nil) and (ap_in ~= nil))
local self = {
name = name_in,
ap = ap_in
}
return setmetatable(self, Item)
end
return Item
From there, I wrote a main driver to encapsulate some of the behavior you described in your question. (Yes, I know my Lua code looks more like C.)
#!/usr/bin/lua
-------------
-- Modules --
-------------
local Item = assert(require("Item"))
local function eprintf(fmt, ...)
io.stderr:write(string.format(fmt, ...))
return
end
local function printf(fmt, ...)
io.stdout:write(string.format(fmt, ...))
return
end
local function getline()
local read = tostring(io.read("*l"))
return read
end
local function main(argc, argv)
local gold = Item.new("Gold", 3)
printf("gold.name = %s\ngold.ap = %i\n", gold.name, gold.ap)
return 0
end
main(#arg, arg)
Now, as for the reverse search which you described, at this point all you should have to do is check the user's input against an Item's name. Here it is in the main function:
local function main(argc, argv)
local gold = Item.new("Gold", 3)
local bag = {}
eprintf("What are you trying to take? ")
local input = getline()
if (input == gold.name) then
table.insert(bag, gold)
eprintf("You took the %s.\n", gold.name)
else
eprintf("Unrecognized item `%s`.\n", input)
end
return 0
end
I hope this helps!

Append elements to a Lua table from variables / Clearing a Lua table

I make a function to parsing path name and file name from a computer directory using Lua Cheat Engine, next I want store the results in to a Lua table.
My function :
function addSongList()
load_dialog = createOpenDialog(self)
load_dialog.InitalDir = os.getenv('%USERPROFILE%')
load_dialog.Filter = 'MP3 files|*.mp3|*'
load_dialog.execute()
file = load_dialog.FileName
if file then
--- parsing path and filename
local pathN = file:match("(.*[\\/])")
local path, name = file:match('(.*\\)(.*)%.mp3')
--- test to open E:\MyMP3\mysong.mp3
print(pathN) --- result : E:\MyMP3\
print(name) --- result : mysong.mp3
end
end
local mp3Table = {}
table.insert(mp3Table,{pathN,name})
Is this correct way and correct syntax using table.insert(mp3Table,{pathN,name})
How to check if elements already added to the table by print out them?
How to clearing / empty the table ?
Thank you
1 - Inserting to the table:
table.insert(tb, value) inserts the value to de table tb. Using table.insert(mp3Table,{pathN,name}) you are dynamically creating a (sub)table and then appending to the main one.
2 - Printing the table.
As already pointed out you can just traverse the table using pairs or ipairs in order to get the elements.
I prefer ipairs in this case because the table is numerically indexed and order is guaranteed in accordance to table.insert.
The inner table must be indexed by numbers because you created it usign numeric indices.
for k, v in ipairs(mp3Table) do
print(v[1], v[2])
end
But you can also opt for a metatable which will also give you the possibility to generate a string representation for the table:
mp3Table_mt =
{
__tostring = function(self)
local ret = {}
for k, v in ipairs(self) do
table.insert(ret, v[1] .. "\t" .. v[2])
end
return table.concat(ret, "\n")
end
}
When initializing mp3Table you have to assign the metatable
local mp3Table = setmetatable({}, mp3Table_mt)
Then you can just tell Lua to print the table:
print(mp3Table)
3 - Empty/Delete the table:
Well there are two different things here. One is empty another is delete.
Lua uses garbage collection so actual deleting only occurs when there are no more references to a particular table. What you can do to tell Lua you no longer need a variable is assing nil to it. If there is no other reference to the value your variable was pointing to, the GC will clean it when it runs.
But you can empty the table without deleting it.
It may be tempting to say that mp3Table = {} "empties the table". But it does not.
What you are doing in this case is assigning a fresh new table to mp3Table variable. And if any other variable is still pointing to the old table it will no get collected and the inner values will remain untouched. If there's no such other variable, the table will be garbage collected just as if you assigned nil to mp3Table variable.
So to effectivelly empty a table you have to traverse it and set all its variables to nil.
function clearTable(tb)
for i, v in pairs(tb) do
tb[i] = nil
end
end
Specifically in the case asked, just assigning a new table to mp3Table may be enough because there are no more references to the same table. Assign nil afterwards is not necessary. What matters is if there are variables pointing to the same value. If you know what you are doing and the consequenses then no problem go ahead.
Putting it all together:
mp3Table_mt =
{
__tostring = function(self)
local ret = {}
for k, v in ipairs(self) do
table.insert(ret, v[1] .. "\t" .. v[2])
end
return table.concat(ret, "\n")
end
}
function addSongList(mp3Table)
local load_dialog = createOpenDialog(self)
load_dialog.InitalDir = os.getenv('%USERPROFILE%')
load_dialog.Filter = 'MP3 files|*.mp3|*'
load_dialog.execute()
file = load_dialog.FileName
if file then
--- parsing path and filename
local pathN = file:match("(.*[\\/])")
local path, name = file:match('(.*\\)(.*)%.mp3')
--- test to open E:\MyMP3\mysong.mp3
print(pathN) --- result : E:\MyMP3\
print(name) --- result : mysong.mp3
table.insert(mp3Table,{pathN,name})
end
return mp3Table
end
function clearTable(tb)
for i, v in pairs(tb) do
tb[i] = nil
end
end
local mp3Table = setmetatable({}, mp3Table_mt)
print(addSongList(mp3Table))
clearTable(mp3Table) -- I'm not assigning a new one. Just clearing the fields.
print(mp3Table) -- Must print nothing
1)yes
2)printing table in cycle:
for k,v in pairs(mp3Table) do
print( v.pathN, v.name)
end
3)empty table
mp3Table = {} -- clean
mp3Table = nil -- delete

Slplit IPv4 address to minimum and maximum range

Using Lua how do I split a given IP address to get the minimum and maximum range for example:
94.19.21.119
I have a csv like this:
18087936,18153471,"AU"
18153472,18219007,"JP"
18219008,18350079,"IN"
18350080,18874367,"CN"
thats read to 3 tables and the csv is min,max,country code:
IPfrom = {}
IPto = {}
IPCountry = {}
they get populated like this:
IPfrom[18087936] = L
IPto[L] = 18153471
IPCountry[L] = "AU"
with L being the line number of the io.read, what Im then trying to do is get the minimum range so I can without looping check if it exists then if it does that key holds the index of the maximum range and if the ip is within the min/max I get the country code. Probably a different way of doing things but the tables are over 100000 entries so looping is taking some time.
Perhaps something like the following will work for you:
--
-- Converts an IPv4 address into its integer value
--
function iptoint(ip)
local ipint = 0
local iter = string.gmatch(ip, "%d+")
for i = 3, 0, -1 do
local piece = tonumber(iter())
if piece == nil or piece < 0 or piece > 255 then
return nil
end
ipint = bit32.bor(ipint, bit32.lshift(piece, 8 * i))
end
return ipint
end
--
-- Looks up an IPv4 address in a multidimensional table, with the entries:
-- {start_address, end_address, country}
-- and returns the matching country
--
function iptocountry(ip, tbl)
local ipint = iptoint(ip)
if ipint == nil then
return nil
end
for _,v in pairs(tbl) do
if ipint >= v[1] and ipint <= v[2] then
return v[3]
end
end
return nil
end
Example usage:
local countries = {
{16777216, 17367039, "US"},
{1578300000, 1678300000, "CAN"}
-- ... rest of entries loaded from CSV file
}
local ip = "94.19.21.119"
print (iptocountry(ip, countries)) -- prints CAN
A hash table (the basic type in Lua) will give you O(N). An array (a table with no holes with indices from someMinAddr to someMaxAddr) will give you O(1), but use a significant amount of memory. A binary search through a properly sorted structured table could give you O(log N), which for 100000 addresses is probably worth the effort. I imagine you could have a structure like this:
IPfrom = {
{line=L1, addFrom=from1, addrTo=to1, c=country1},
{line=L2, addFrom=from2, addrTo=to2, c=country2},
{line=L3, addFrom=from3, addrTo=to3, c=country3},
{line=L4, addFrom=from4, addrTo=to4, c=country4},
...
}
because I don't see the point of separating the to and country fields from the other info, just means more table lookup. Anyways if you really do want to separate them the following is not affected:
-- init:
create table from CSV file
sort IPFrom on addFrom field
-- as many times as required:
function findIP(addr)
is addr smaller than IPfrom[middle].addrTo3?
if yes, is addr smaller than IPfrom[middle of middle]?
etc
end
This is recursive so if you structure it properly you can use tail calls and not worry about stack overflow (;), something like
function findIPRecurs(addr, ipTbl, indxMin, indxMax)
local middle = (indxMin + indxMax )/2
local midAddr = ipTbl[middle].addrFrom
if addr < midAddr then
return findIPRecurs(addr, ipTbl, indxMin, middle)
else if addr > midAddr then
return findIPRecurs(addr, ipTbl, middle, indxMax)
else -- have entry:
return middle
end
end
function findIP(addr)
return findIPRecurs(addr, ipTbl, 1, #ipTbl)
end
I have not tested this so there might be some fixing up to do but you get the idea. This will use the same memory as O(N) method but for large arrays will be considerably faster; much less memory than O(1) method, and probably acceptably slower.

lua Hashtables, table index is nil?

What I'm currently trying to do is make a table of email addresses (as keys) that hold person_records (as values). Where the person_record holds 6 or so things in it. The problem I'm getting is that when I try to assign the email address as a key to a table it complains and says table index is nil... This is what I have so far:
random_record = split(line, ",")
person_record = {first_name = random_record[1], last_name = random_record[2], email_address = random_record[3], street_address = random_record[4], city = random_record[5], state = random_record[6]}
email_table[person_record.email_address] = person_record
I wrote my own split function that basically takes a line of input and pulls out the 6 comma seperated values and stores them in a table (random_record)
I get an error when I try to say email_table[person_record.email_address] = person_record.
But when I print out person_record.email_address it's NOT nil, it prints out the string I stored in it.. I'm so confused.
function split(str, pat)
local t = {} -- NOTE: use {n = 0} in Lua-5.0
local fpat = "(.-)" .. pat
local last_end = 1
local s, e, cap = str:find(fpat, 1)
while s do
if s ~= 1 or cap ~= "" then
table.insert(t,cap)
end
last_end = e+1
s, e, cap = str:find(fpat, last_end)
end
if last_end <= #str then
cap = str:sub(last_end)
table.insert(t, cap)
end
return t
end
The following code is copy and pasted from your example and runs just fine:
email_table = {}
random_record = {"first", "second", "third"}
person_record = {first_name = random_record[1], last_name = random_record[1], email_address = random_record[1]}
email_table[person_record.email_address] = person_record
So your problem is in your split function.
BTW, Lua doesn't have "hashtables". It simply has "tables" which store key/value pairs. Whether these happen to use hashes or not is an implementation detail.
It looks like you iterating over some lines that have comma-separated data.
Looking at your split function, it stops as soon as there's no more separator (,) symbols in particular line to find. So feeding it anything with less than 3 ,-separated fields (for very common example: an empty line at end of file) will produce a table that doesn't go up to [3]. Addressing any empty table value will return you a nil, so person_record.email_address will be set to nil as well on the 2nd line of your code. Then, when you attempt to use this nil stored in person_record.email_address as an index to email_table in 3rd line, you will get the exact error you've mentioned.

Resources