how to batch change the field of the table in lua - lua

In lua, now I want to change field name of a table, like
in test1.lua
local t = {
player_id = 2,
item_id = 1,
}
return t
in test2.lua
local t = require "test1"
print( t.item_id )
if I want to change field name item_id -> item_count of t,
I need to use the application like ultraedit, find out all lua file contain item_id, and modified one by one, such modification easy correction or change of leakage, is there any tools can be more easily modified the field name?

If I understand your problem correctly:
(What if item_id also happens to be a field in a different table?)
In my view, there is no generic solution for this task without actually interpreting the script. A field name (e.g., item_id) could appear in many places but be referring to different tables. To make sure you change only references to the correct table you need to actually interpret the script. Given the dynamic nature of Lua scripts, this is not a trivial task.
Using an editor (or preferably a Lua script) to globally replace all occurrences of one name to another will only work if you're certain the 'old' name has only a single context.
A run-time workaround might be to add some metatable to keep both the new and the old name. I think you need to play with the __index and __newindex events. Then, the same field will be accessed by either 'old' or 'new' name.
Example for the metatable trick (only field 'one' is actually part of the table, field 'two' access is made possible via the metatable to read/write field 'one' so that reading from 'two' reads 'one', while writing to 'two' writes to 'one'):
t = {}
t.one = 1
setmetatable(t,{__index = function(t,k)
if k == 'two' then return t.one end
end,
__newindex = function(t,k,v)
if k == 'two' then t.one = v end
end
})
print(t.one,t.two)
t.two = 2
print(t.one,t.two)

Related

LUA - Getting values from nested table

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.

Strange bug with table in lua

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

Lua get value of a table in n tables

I have a problem,
I must change a value in a known table which is located in n tables before.
Something like this:
Box = {
{Name = "",Box = {{Name = "",Box = {{Name = "", Box = {{Name = "This must be change for the test",Box = {}}}}}}}}
}
To change this I can hardcode this with:
Box[1].Box[1].Box[1].Box[1].Name = "Changed"
But this isn't the way I want it!
I want to change this dynamically, so that I have one function which can change the value 'x' of table 'n' in the main table 'tbl'.
Is there any way to do this?
With the problem like that you probably should rethink your design choices. That table in n tables, you describe is akin to a tree graph where field box holds the references to children nodes.
As your comments state, you have the need of modifying a node located on a dynamic path in that tree. A simple function is obvious:
local function follow_path(start_node, path,i)
--takes start node and array of indices to follow
--returns table that is stored in the box-tree at this path
--i is for internal recursion
i=i or 1
if not path[i] then
return start_node
else
local new_start=start[path[i]]
assert(new_start,"No node is on this path")
return follow_path(new_start,path,i+1)
end
end
local function follow_path_and_rename(start_node,path,field_name,new_value)
local box = follow_path( start_node,path)
box[field_name] = new_value
end
But, depending on why do you need to modify a node with dynamic path there might be more solid approaches. One thing that never hurts is to give each of your boxes a unique identifier during its creation:
local new_box
do
local box_count=0
new_box = function(name)
box_count=box_count+1
local box = {
unique_id=box_count,
name=name,
box={}
}
return box
end
end
With that you could for example create index table where your boxes are always accessible by their id:
local index={}
local add_new_box = function(name)
local box = new_box(name)
index[ box.unique_id] = box
return box
end
Or if that is unacceptable, you could always search through the nodes of tree for a node that is guaranteed to have unique value.
But the thing is: all the tables do already have unique identifier. It is their address, the value that gets assigned to a when you do a = {}. The only differences between that, and the unique_id are:
1)a is not quite as readable.
2) if you know a, you don't need to search for it.
So, take a look at your problem, take a look and ask yourself:
"Where this need comes from? Why cannot I get unique_id instead a sequence of indices? Why cannot I get the box itself instead of unique_id?"

Confusion of using "." notation with __index and namespace in Lua

I am confused of the following two syntaxes using "."
From what I understand, __index is called when a key doesn't exist in a table but exists in its metatable. So why does the list table call __index and then assign itself to list.__index?
list = {}
list.__index = list
setmetatable(list, { __call = function(_, ...)
local t = setmetatable({length = 0}, list)
for _, v in ipairs{...} do t:push(v) end
return t
end })
function list:push(t)
if self.last then
self.last._next = t
t._prev = self.last
self.last = t
else
self.first = t
self.last = t
end
self.length = self.length + 1
end
.
.
.
local l = list({ 2 }, {3}, {4}, { 5 })
Does Window.mt simply create a table? Why do we need Window = {} as a namespace here?
Window = {} -- create a namespace
Window.mt = {} -- create a metatable
Window.prototype = {x=0, y=0, width=100, height=100, }
function Window.new (o)
setmetatable(o, Window.mt)
return o
end
Window.mt.__index = function (table, key)
return Window.prototype[key]
end
w = Window.new{x=10, y=20}
print(w.width) --> 100
So why does the list table call __index and then assign itself to list.__index?
Nowhere in your code does the list table call __index. The assignment part however is a common Lua idiom (aka. hack) to save some memory. Conceptually there are 4 different kinds of tables involved:
list objects (the tables created via {length=0} in your code)
a metatable (containing an __index field) that modifies the behavior of list objects when you try to access non-existing fields in the object
the list class, which holds all the methods for list objects (like the push method), and also serves as a constructor for list objects
a metatable (containing a __call field) for the list class, so that you can call the list table as if it were a function
As metatable fields always start with two underscores (__), and normal methods usually don't, you can put metatable fields and normal methods side by side into a single table without conflict. And this is what happened here. The list class table also serves as metatable for list objects. So using this trick you can save the memory you would normally need for the separate metatable (the size in bytes for Lua 5.2 on an x86-64 Linux is shown in square brackets in the table title bars, btw.):
Does Window.mt simply create a table?
No, {} creates a table. However, this new table is saved under key "mt" in the Window table, probably to give users of this Window "class" direct access to the metatable that is used for window objects. Given only the code you showed this is not strictly necessary, and you could have used a local variable instead.
Why do we need Window = {} as a namespace here?
In principle, you could store Window.mt, Window.new, and Window.prototype separately, but that would get cumbersome if you have multiple "classes" like Window. This way you can avoid name clashes, and using the Window "class" looks nicer.
Another reason might be that require can only return a single value from a module definition, and if you want to export multiple values (like new, mt, and prototype) from a module, you need a table to wrap them together (or use global variables, but that is considered bad style).

Lua: getting environment of element that belongs to specified table

Is it possible to check if some object is really element of specified table? I tried to use debug.getfenv(o) but didn't work.
someTable = {}
someTable.someValue = "Some String"
--gettable(someTable.someValue)
--so that could return table that stores someValue: someTable
getfenv is so named because it returns a function's environment. Because only functions have environments.
Values in Lua have no particular knowledge of which tables that they're in. If you need to know that, you'll have to keep track of it yourself.

Resources