I am trying to make a table, name given by the first arg of a function and assign a value to a key named by the second arg. For example
function myinsert(a, b)
a.b = 10
For example when I give args pencil and price, pencil table to be created and pencil.price to be 10. Or other args, lesson and grade, making lesson.grade = 10. But as I try this it gives that it can't index local a (number value). What should I do? Thanks a lot
You can use the loadstring function, which will evaluate arbitrary code in string
http://www.lua.org/pil/14.1.html
Example:
function myinsert(a, b)
f = loadstring(string.format("%s={}; %s.%s=10", a, a, b))
f()
You can use _G[a]={[b]=10} to create a global table whose name is stored in a. The name of field to receive 10 is stored in b.
For example:
a = "pencil"
b = "price"
_G[a]={[b]=10}
is the same as
pencil.price=10
The code works even if a or b are not really names, that is, they don't have to be strings.
Related
Example:
mytable = {{id=100,wordform="One Hundread"},{id=200,wordform="Two Hundread"}}
I want to be able to access the row based on the id to do something like this:
mynum = 100
print ("The value is " .. mytable[mynum].wordform)
The main point here is I want to be able to set the index value so I can predictably retrieve the associated value later as I might do with a java hashmap.
Ideally your table should just use the ID as key:
local mytable = {[100] = {wordform = "One hundred"}, [200] = {wordform = "Two hundred"}}
print("The value is " .. mytable[100].wordform)
If your table is in list form, you can convert it to ID form rather easily:
local mytable_by_id = {}
for _, item in pairs(mytable) do mytable_by_id[item.id] = item end
Using the hash part of a Lua table is definitely preferable over looping over the list entries in linear time as Renshaw's answer suggests (the fact that it's hidden behind a metatable may hide the poor performance and trick the reader into believing a hash indexing operation is taking place here though).
Furthermore, that answer won't even work correctly, as the list part uses integer keys as well; IDs that are valid list part indices would possibly return the wrong element. You'd have to use a function instead of a metatable.
you can use metatable
setmetatable(mytable, {__index = function(tbl, id)
for _, item in pairs(tbl) do
if type(item) == "table" and item.id == id then
return item
end
end
end})
then
mynum = 100
print ("The value is " .. mytable[mynum].wordform) -- The value is One Hundread
I have a table which will be used to store each players name, id and another value
{
{
rpname = "name",
SteamID = "STEAM_0:0:",
giftsFound = "1",
},
The table is being sent from server to client via net.ReadTable()
I want to be able to choose each value seperatley but when I have tried the following below it only returns the first letter of every value instead of the first value
for k, v in pairs(tableData) do
for k, v in pairs(v) do
print(v[1]
end
end
Please could somebody help me out?
If I understood correctly, the sample table you wrote in the first block of code would be what you called tableData in the second, right? So, what you want to have is:
An array of players
Each entry in this array is a table
A way of getting each field of each player
With a few tweaks we can make your code more readable and, from that, correct it. Firsly, I would rename some things:
Rename your table players, for it is an array of players
local players = {
{
rpname = "john",
SteamID = "STEAM_0:0:1",
giftsFound = "4",
},
-- [...]
}
Rename your variables in the for-loop
In Lua it is common pratice to use _ to name variable we are not going to use. In this case, the key (originally named k) is not something we will use.
Since it is a list of players, each entry is a player, so it is logical to rename the variable v to player.
Also, I changed pairs() to ipairs() and there's a good reason for that. I won't cover it here, but here it is explained as best as I could. Rule of thumb: if your table is array-like, use ipairs(); else, use pairs().
for _, player in ipairs(players) do
-- [...]
end
For the nested for-loop, it does make sense using k, v and pairs, so it would be something like this:
for k, v in pairs(player) do
print(k,v)
end
Running the full piece would produce this:
rpname john
giftsFound 4
SteamID STEAM_0:0:1
I suppose it solves your problem. The real errors in your code were the way you tried to access the nested table field and, arguably, naming variables with names you have already used (k and v) in the same scope, which is, in the best case, misleading.
If you want to access a specific field in the table, instead of going through the whole thing, you can do:
-- To print every player's name
for _, player in ipairs(players) do
local name = player.rpname
print(name)
end
Or even:
-- To get the first player's (in the array) name
local name = players[1].rpname
One last thing: "Lua" is not an acronym, you don't need to use all capital letters. Lua was created in Brazil and here we speak portuguese. Lua means Moon in portuguese.
I'm adding a string to a table in lua. When I use the table in a function the original table is getting altered. I'm only a beginner but I thought that the function could not do that because it is outside of it's scope. Is there something obvious I'm missing?
local testTable= {}
testTable.name = {}
testTable.name[1] = "Jon"
print(testTable.name[1])
local function testFunc(a)
a.name[1] = "Bob"
end
local newTable = testTable
testFunc(newTable)
print(testTable.name[1])
I expected the output to be:
Jon
Jon
The actual output is:
Jon
Bob
How can the testFunc change the testTable?
You assign testTable's address to newTable, so testTable and newTable point to the same table.
If you want to output be
Jon
Jon
You should copy the table when you assign newTable.
You can copy the table like this function:
function table.copy(old)
local new = {}
for k, v in pairs(old) do
new[k] = v
end
return new
end
When I use the table in a function the original table is getting altered. ... I thought that the function could not do that because it is outside of it's scope.
Local variables have their own scope, but tables do not. Two things to remember:
Variables store references, not values. (This only makes a difference for mutable values.)
Tables are mutable, i.e., they can be changed internally.
Breaking it down:
local newTable = testTable
In this line, you're assigning one variable to another, so both variables refer to the same table.
We mutate a table by assigning to an index within that table, so testFunc alters whatever a (actually a.name) refers to. This is handy, because it allows us to write functions that mutate tables that we pass as arguments.
The following function does nothing, like you would expect, because it assigns a new table to the bare name a (which happens to be a local variable):
local function doNothing(a)
a = {name = {'Bob'}}
end
I got a question on how to use dynamic variable names with the table.insert function in Lua.
I want to create some tables with dynamic variable names and afterwards access those tables using table.insert function to fill them with values, however, I am unclear on how to access the newly created table inside of the table.insert function.
My code so far looks like this:
local attributeNames = {"attribute1","attribute2","attribute3"}
local attributes = {}
for k, v in pairs(attributeNames) do
// If attribute name equals name of type then create a new table with
that type name
if(string.match(v, type)) then
attributes[v] = {}
currentAttribute = v
break
end
end
// Insert values into the table with that type name, here I do not get how to call
the table of name "attribute1" for example to fill it with values
table.insert (attributes[currentAttribute], values)
Any help is highly welcome! :)
In Lua, I can add an entry inside table with table.insert(tableName, XYZ). Is there a way I can add already existing table into table? I mean a directly call rather then traversing and add it.
Thanks
The insert in your example will work fine with whatever contents happen to be inside the XYZ variable (number, string, table, function, etc.).
That will not copy the table though it will insert the actual table. If you want to insert a copy of the table then you need to traverse it and insert the contents.
First: In general, you do not need table.insert to put new entries into tables.
A table in Lua is a collection of key-value pairs; entries can be made like this:
local t = {} --the table
local key= "name"
local value = "Charlie"
t[key] = value --make a new entry (replace an existing value at the same key!)
print(t.name) --> "Charlie"
Note that key can have any type (not just integer/string)!
Very often you will need tables for a simple special case of this: A sequence ("list", "array") of values. For Lua, this means you want a table where all the keys are consecutive integers, and contain all non-nil values. The table.insert function is intended for that special case: It allows you to insert a value at a certain position (or to append it at the end of the sequence if no position is specified):
local t = {"a", "b", "d"} --a sequence containing three strings (t[1] = "a", ...)
table.insert(t, "e") --append "e" to the sequence
table.insert(t, 3, "c") --insert "c" at index 3 (moving values at higher indices)
--print the whole sequence
for i=1,#t do
print(t[i])
end
If I understand what you mean correctly, you want to do this:
local t1 = {1, 2, 3}
local t2 = {4, 5, 6}
some_function(t1, t2)
-- t1 is now {1, 2, 3, 4, 5, 6}
There is indeed no way to do this without iterating t2. Here is a way to write some_function:
local some_function = function(t1, t2)
local n = #t1
for i=1,#t2 do t1[n+i] = t2[i] end
end
No, you must copy the second table's key/value pairs into the first table. Copying the existing values from the second table is what's known as a "shallow copy." The first table will reference the same objects as the second table.
This works under limited circumstances:
local n = #t1
for i=1,#t2 do t1[n+i] = t2[i] end
It does attempt to shift the t2 elements to just beyond the existing t1 elements. That could be a vital requirement but wasn't stated in the question.
It has a few of problems, though:
By using #t1 and #t2, it misses keys that aren't positive integers and can miss keys that are integers greater than a skipped integer key (i.e. never assigned or assigned nil).
It accesses the first table with an indexer so could invoke the __newindex metamethod. That probably wouldn't be desirable when only copying is wanted.
It accesses the second table with an indexer so could invoke the __index metamethod. That wouldn't be desirable when only copying is wanted.
You might think that ipairs could be used if only positive integer keys are wanted but it quits on the first nil value found so could miss even more than #t2 does.
Use pairs instead:
for key, value in pairs(t2) do
rawset( t1, key, value )
end
If you do want to avoid replacing existing t1 values when the keys match or otherwise map t2 keys in some way then that has to be defined in the requirements.
Bottom line: pairs is the way to get all the keys. It effectively does a rawget so it avoids invoking __index. rawset is the way to do a copy without invoking __newindex.