Is it possible to have a function that can access arbitrarily nested entries of a table?
The following example is just for one table. But in my real application I need the function to check several different tables for the given (nested) index.
local table1 = {
value1 = "test1",
subtable1 = {
subvalue1 = "subvalue1",
},
}
local function myAccess(index)
return table1[index]
end
-- This is fine:
print (myAccess("value1"))
-- But how do I access subtable1.subvalue1?
print (myAccess("subtable1.subvalue1???"))
You won't be able to do this using a string unless you use load to treat it as Lua code or make a function to walk on a table.
You can make a function which will split your string by . to get each key and then go one by one.
You can do this using gmatch + one local above gmatch with current table.
#Spar: Is this what you were suggesting? It works anyway, so thanks!
local table1 = {
value1 = "test1",
subtable1 = {
subvalue1 = "subvalue1",
},
}
local function myAccess(index)
local returnValue = table1
for key in string.gmatch(index, "[^.]+") do
if returnValue[key] then
returnValue = returnValue[key]
else
return nil
end
end
return returnValue
end
-- This is fine:
print (myAccess("value1"))
-- So is this:
print (myAccess("subtable1.subvalue1"))
Related
I recently wrote some code like this:
function enum(tbl)
local length = #tbl
for i = 1, length do
local v = tbl[i]
tbl[v] = i
end
return tbl
end
eItemType = enum
{
"wpn",
"outf",
"helm",
"art",
"boost",
"bkpk",
"dev",
"ammo",
"none"
}
It works. But I would like to simplify it to this form:
enum eItemType
{
"wpn",
"outf",
"helm",
"art",
"boost",
"bkpk",
"dev",
"ammo",
"none"
}
For the enum function to create a global variable eItemType in the file from which it is called.
I don't know how to implement this (convert eItemType to string in string code).
Functions from the debug library come to mind, namely getline, maybe it can handle it...
Enumerations in Lua
First of all: You're shoehorning a foreign language concept into Lua, which will necessarily not be round on the corners. Languages like C use numbers (integers) for enums because of their efficiency: Integer comparison is fast. In the end, enums are just synctactic sugar for enumerating integer constants though. You don't need any of this in Lua: Lua has string interning, which means strings are only stored once in memory and can be compared as fast as numbers. That is, the naive way to implement enums in Lua, is to simply use strings right away!
local enum_values = {"foo", "bar", "baz"}
local function get_random_enum_value()
return enum_values[math.random(#enum_values)]
end
if get_random_enum_value() == "foo" then
print("Congratulations! The value is foo!")
end
The downside is that you now don't have any table holding your enum values, so you'll either want to brush up on your documentation or create a (redundant) hash table to hold your enum values (which really is just making things slower, but may help readability). You don't need to involve any numbers. If I inspect a table and see a "foo_something" string there, that's a lot more useful than 42.
local my_enum = {foo = "foo", bar = "bar", baz = "baz"}
local enum_values = {my_enum.foo, my_enum.bar, my_enum.baz}
local function get_random_enum_value()
return enum_values[math.random(#enum_values)]
end
-- May be considered more readable since we now have a scope for "foo"
if get_random_enum_value() == my_enum.foo then
print("Congratulations! The value is foo!")
end
then you'd probably write yourself a simple helper to generate these kinds of tables:
function enum(namelist)
local t = {}
for _, v in pairs(namelist) do
t[v] = v
end
return t
end
my_enum = enum{
"foo",
"bar",
"baz",
}
Syntactic Sugar
What you want is called syntactic sugar and yes, it requires Lua's metaprogramming capabilities. If you really want an enum keyword, you'll have to extend Lua or implement a preprocessor adding such a keyword.
First, let's see how Lua sees your current code:
someName = enum { ... }
parses as "call the variable called enum with the table { ... } and assign the result to the variable called someName".
enum someName { ... }
does not parse: this is just a name, followed by... another name? Syntax error. By slightly abridging this syntax, it is however still possible to turn this into a valid expression. How about passing someName as a string to enum, which then returns a function to apply to your table?
enum "someName" { ... }
this would be implemented as
function enum(name)
return function(t)
_G[name] = original_enum(t)
end
end
where original_enum is your original enum function without the added layer for syntactic sugar. You might want to swap out _G with _ENV or getfenv(2) or similar.
Or for another syntactic sugar, you could also use the indexing operator paired with the __index metamethod:
enum.someName { ... }
which is implemented as:
enum = setmetatable({} --[[proxy table]], {__index = function(_, name)
return function(t)
_G[name] = original_enum(t)
end
})
both of these have in common that they are basically just fancy ways of currying the name of the global variable you want to assign to.
f you need to get a table from a string, then try:
local s = [[ return {
"wpn",
"outf",
"helm",
"art",
"boost",
"bkpk",
"dev",
"ammo",
"none"
}]]
eItemType = (loadstring or load)(s)() -- since Lua 5.2 loadstring has been replaced by load
for k,v in pairs(eItemType) do
print( k,v)
end
if you need a full copy of a simple table , then it is created like this:
enum = function(t)
local tmp = {}
for _,v in ipairs(t) do tmp[#tmp+1]=v end
return tmp
end
eItemType = enum {
"wpn",
"outf",
"helm",
"art",
"boost",
"bkpk",
"dev",
"ammo",
"none"
}
if you need to move the creation of a global table or enumerations to another place, look at the solution through modules
and the last solution is to get a line of code from a simple table, used to write to a file and generate lua code
function dumpValue(obj)
local s = '\n{ '
for k,v in ipairs(obj) do
s = s .. '\n['..k..'] = "' .. v .. '",'
end
return s .. '} '
end
print(dumpValue(eItemType))
In the command
table.insert(table, data)
how can you use that but for the inserts have string keys?
PSEUDO CODE
tableOfStuff = {cat, pig, hat, lemon}
t = {}
for i=1, #tableOfStuff do
table.insert(t, key=tableOfStuff[i], data=tableOfStuff[i])
end
So I end up with a table...
t['cat'] == 'cat'
t['dog'] == 'dog'
etc.....
EDIT
I think my example confused people... I am asking how to use "insert.table" but insert tings with string keys...
table.insert(table,data,stringkey)
something like this?
Creating One Table
If all you want is to create a table with strings as keys, then check out Table Constructors, you have a couple options.
Option 1:
t = { key1 = "value1", key2 = "value2" }
--or like this:
t = { ["key1"] = "value1", ["key2"] = "value2" }
Option 2: (create an empty table first)
t = {}
t.key1 = "value1"
--or like this
t["key2"] = "value2"
It looks like you want the keys and values to be the same string and that is possible. Just write the same thing for key1 and value1. So t["cat"] = "cat".
Using Two Tables
Based on your example code, it looks like you want to take an existing table of strings and create from that a new table with strings as both the keys and the values. To do that:
table1 = { "cat", "pig", "hat", "lemon" }
table2 = {}
for i=1, #table1 do
table2[ table1[i] ] = table1[i]
end
--test
print table2["cat"]
Here is a good lesson about tables in Lua: Lua Tables Tutorial
The comment is right.You needn't and you can't use table.insert.You can see the document table.insert.It's only support the number.It' used for the array part of table.But you're using the hash part of a table.
code:
tableOfStuff = {"cat", "pig", "hat", "lemon"}
t = {}
for i=1, #tableOfStuff do
local szKey = tableOfStuff[i];
t[szKey] = tableOfStuff[i]; -- the value can be the others.
end
I am new to Lua and I am trying to learn how to make a function with embedded tables. I am stuck trying to figure out a way to make the function meet specific values in the table.
Here is an example of a table:
TestTable = {destGUID1 = {catagory1 = {A=1,B=5,C=3},catagory2 = {A=5,B=3,C=2}},destGUID2 = {catagory1 = {A=1,B=5,C=3},catagory2 = {A=5,B=3,C=2}}}
Now I want to make a function for this table that pulls values only from the specific destGUID. Like:
function CatInfo(GUID,Cat)
for i=1, #TestTable do
if TestTable[i] == GUID then
for j=1, TestTable[i][GUID] do
if TestTable[i][GUID][j] == Cat then
return TestTable[i][GUID][Cat].A -- returns value "A"
end
end
end
end
end
So that when I use this function, I can do something like this:
CatInfo(destGUID2,catagory1) -- returns "1"
Given your table structure, you don't need to do any looping; you can simply return the value from the table based on GUID and the category:
TestTable = {
destGUID1 = {catagory1 = {A=1,B=5,C=3},catagory2 = {A=5,B=3,C=2}},
destGUID2 = {catagory1 = {A=1,B=5,C=3},catagory2 = {A=5,B=3,C=2}}
}
function CatInfo(GUID,Cat)
return TestTable[GUID][Cat].A
end
print(CatInfo('destGUID2','catagory1'))
This will print 1. Note that destGUID2 and catagory1 need to be in quotes as those are strings.
Backpack = {Potion = 'backpack',Stack = 'bag',Loot = 'derp', Gold = 'random'}
Backpack[1] ~= 'backpack' -- nope
As you guys can see, I cannot call Backpack[1] since its not a numeral table, how would I generate a table after the construction of Backpack, consisting only of it's values? for example:
Table_to_be_Constructed = {Value of Potion,Value of Stack,Value of Loot,Value of Gold} -- this is what i need
It seems simple but I couldn't find a way to do it.
I need it this way because i will run a numeric loop on Table_to_be_Constructed[i]
To iterate over all the key-value pairs in a table, use the pairs function:
local Table_to_be_Constructed = {}
for key, value in pairs(Backpack) do
table.insert(Table_to_be_Constructed, value)
end
Note: the iteration order is not defined. So, you might want to sort Table_to_be_Constructed afterwards.
By convention, the variable name _ is used to indicate a variable who's value won't be used. So, since you want only the values in the tables, you might write the loop this way instead:
for _, value in pairs(Backpack) do
For the updated question
Backpack has no order (The order in the constructor statement is not preserved.) If you want to add an order to its values when constructing Table_to_be_Constructed, you can do it directly like this:
local Table_to_be_Constructed = {
Backpack.Potion,
Backpack.Stack,
Backpack.Loot,
Backpack.Gold
}
Or indirectly like this:
local items = { 'Potion', 'Stack', 'Loot', 'Gold' }
local Table_to_be_Constructed = {}
for i=1, #items do
Table_to_be_Constructed[i] = Backpack[items[i]]
end
I was wondering whether it is possible to display tables in the console. Something like:
player[1] = {}
player[1].Name = { "Comp_uter15776", "maciozo" }
InputConsole("msg Player names are: " .. player[1].Name)
However, this is obviously wrong as I receive the error about it not being able to concatenate a table value. Is there a workaround for this?
Much thanks in advance!
To turn an array-like table into a string, use table.concat:
InputConsole("msg Player names are: " .. table.concat(player[1].Name, " "))
The second argument is the string placed between each element; it defaults to "".
to make life easier on yourself for this... i'd recommend naming elements in the inner tables as well. this makes the code above easier to read when you need to get at specific values in a table that are meaningful for some purpose.
-- this will return a new instance of a 'player' table each time you call it.
-- if you need to add or remove attributes, you only need to do it in one place.
function getPlayerTable()
return {FirstName = "", LastName = ""}
end
local players = {}
local player = getPlayerTable()
player.FirstName = "Comp_uter15776"
player.LastName = "maciozo"
table.insert(players, player)
... more code to add players ...
local specific_player = players[1]
local specific_playerName = specific_player.FirstName..
" ".. specific_player.LastName
InputConsole("msg Some message ".. specific_playerName)