PDA

View Full Version : Lua array value by string



Xarxus
April 9th, 2023, 15:03
I have the following information in LUA:



local a = "myTable.elem2.sub2";

myTable = {
["elem1"] = {
["sub1"] = "abc",
["sub2"] = "def",
["sub3"] = "ghi",
},
["elem2"] = {
["sub1"] = "jkl",
["sub2"] = "mno",
["sub3"] = "pqr",
},

}

Considering that there could be many structures and I don't know the fields of these, how can I get the value of the field whose name is contained in the variable "a"?

I need to get "mno"

local b = [something](a)

bayne7400
April 9th, 2023, 15:51
Edit. Nm it is a table. Use a for loop.

For k, v in pairs(MyTable) do


End

Debug k and v and I bet you can figure it out. You can also use debugs to work your way through your table when you assign values.

Local rTable = MyTable

Then debug that and see how it looks in FG

bmos
April 9th, 2023, 17:01
if you know the keys:


local myTable = {
["elem1"] = {
["sub1"] = "abc",
["sub2"] = "def",
["sub3"] = "ghi",
},
["elem2"] = {
["sub1"] = "jkl",
["sub2"] = "mno",
["sub3"] = "pqr",
},

}

local a = myTable["elem2"]["sub2"] or myTable.elem2.sub2


if you don't know the keys then you have to iterate over the whole thing:


local myTable = {
["elem1"] = {
["sub1"] = "abc",
["sub2"] = "def",
["sub3"] = "ghi",
},
["elem2"] = {
["sub1"] = "jkl",
["sub2"] = "mno",
["sub3"] = "pqr",
},

}

function printSecondLevelTableValues()
local a
for k, v in pairs(myTable) do
for kk, vv in pairs(v) do
a = vv
Debug.chat(a)
end
end
end

Calling printSecondLevelTableValues() should result in this debug message in chat:
s'abc'
s'def'
s'ghi'
s'jkl'
s'mno'
s'pqr'

Xarxus
April 9th, 2023, 17:40
@bayne7400 and @bmos I know this
local a = "myTable.elem2.sub2";

And it could be another array. All I know is that variable a has the name.
I know that using myTable.elem2.sub2 I can get the value, but i don't know how
to transform "a" value in an espression to take the value from myTable.elem2.sub2
or whatever is "a" value.

Xarxus
April 9th, 2023, 18:30
I tried this in LUA demo (https://www.lua.org/cgi-bin/demo)

myTable = {
["elem1"] = {
["sub1"] = "abc",
["sub2"] = "def",
["sub3"] = "ghi",
},
["elem2"] = {
["sub1"] = "jkl",
["sub2"] = "mno",
["sub3"] = "pqr",
},

}

a="myTable.elem2.sub2"
f=load("return " .. a)
b=f()

print(a)
print(b)


the result is
myTable.elem2.sub2
mno

Now I'll try it in some way in Fantasy Grounds code...
Let's see

Xarxus
April 9th, 2023, 18:47
Uhm, it seems there is no load or loadstring implemented in Fantasy Grounds lua

bmos
April 9th, 2023, 19:47
Uhm, it seems there is no load or loadstring implemented in Fantasy Grounds luaFantasy-Grounds-Specific-Lua-Changes (https://fantasygroundsunity.atlassian.net/wiki/spaces/FGCP/pages/996644496/Ruleset+-+Scripting#Fantasy-Grounds-Specific-Lua-Changes)

bmos
April 9th, 2023, 19:53
I don't think I'm understanding your original question fully, but I think I'm starting to get closer.

If you're trying to look inside a table and path whose names are contained in variable "a" you could try self[a] or something like

a = [ "myTable", "elem2", "sub2" ]
Debug.chat(self[a[1]][a[2]][a[3]])

TheoGeek
April 10th, 2023, 19:52
Edit. Nm it is a table. Use a for loop.

For k, v in pairs(MyTable) do


End

Debug k and v and I bet you can figure it out. You can also use debugs to work your way through your table when you assign values.

Local rTable = MyTable

Then debug that and see how it looks in FG

Also, be careful with assignments like that. I'm pretty sure that will point rTable to the same address that MyTable uses such that if MyTable changes, so does rTable. If you want a completely different table, you need to use the UtilityManager.copyDeep function.

Xarxus
April 10th, 2023, 19:56
I don't think I'm understanding your original question fully, but I think I'm starting to get closer.

If you're trying to look inside a table and path whose names are contained in variable "a" you could try self[a] or something like

a = [ "myTable", "elem2", "sub2" ]
Debug.chat(self[a[1]][a[2]][a[3]])

The problem is that I don't know which array it's using and at what depth. In one case I might have a[1]a[2]a[3], in another
I might have a[1]a[2]...a[n]. What I would like is to have a function that I pass the string "myTable.elem2.sub2....whatever[n]"
to that returns the value of the item being pointed to, no matter how deep it is. With the load it should be possible, without it
seems to me a rather complicated thing.

I hope I managed to make myself understood.

Xarxus
April 10th, 2023, 21:31
Ok, I think I found a solution. Let me know what do you think about it.

Every array I have is in DataCommon, so:



function getFinalValue(sName)
local aNames = StringManager.split(sName[1], ".", true);
local oFinalValue = nil;

for _, aValue in pairs(aNames) do
if oFinalValue == nil then
oFinalValue = DataCommon[aValue];
else
oFinalValue = oFinalValue[aValue];
end
end

return oFinalValue;
end

a="myTable.elem2.sub2";
b = getFinalValue(a);

-- output --> mno



Is there a better way to code it?

UrsaTeddy
April 11th, 2023, 02:04
Without the expression evaluation LUA commands available, your method is as good as any to achieve what you are wanting to do. Since this is your array layout and format, you have achieved the solution that works for you.

My only query would be, why do you have so many unknown tables whose indexes are stored in strings?

Variables in LUA can store tables at any depth, so you can store the table index directly into 'a' (without the quotes) and 'a' would give you your result 'mno'.

If you are generating 'a' from some other source, then that source can easily generate 'a' as a table value rather than a string representing an index.

Something like ...



a = myTable

if condition then
a = a[elem2]

if sub2required then
a = a[sub2]
end

end

return a


As I mentioned I have no idea how or why you are generating your a = "myTable.elem2.sub2", however instead of generating this string, you simply generate the value by making 'a' index itself until you get where you want.

Xarxus
April 11th, 2023, 17:51
I'm actually studying it in a generic way for building controls. It is not a specific need, but a study concerning the functioning and behavior of the code.
Of course I'm also writing for a ruleset on an RPG that a friend of mine has created, but currently I don't have a specific need.

The code I've shown can be augmented to create a version of the load or loadstring functions.
For example:


function myLoad(sName, context)
local aNames = StringManager.split(sName, ".", true);
local oFinalValue = nil;

for _, aValue in pairs(aNames) do
if oFinalValue == nil then
oFinalValue = context[aValue];
else
oFinalValue = oFinalValue[aValue];
end
end

return oFinalValue;
end


In this way it's possible to call it in these ways:


local a = myLoad("myTable.elem2.sub2", DataCommon);
local b = myLoad("myvariable", self); -- this code is not functioning - there is no way to get the environment without the _G variable (not implemented in FG)

Anyway thanks everyone for support (and for putting up with me).

UrsaTeddy
April 11th, 2023, 22:28
I understand that you could write multiple functions to do various things - however my question still stands, why generate the string representation of the data item in the first place instead of return the actual data item.

Then you can pass that data item to a function for further processing.

Xarxus
April 13th, 2023, 08:03
Think of a label whose value is contained in an array, rather than a string definition or constant.
I could extend the control to accept a parameter with the array element.

But this is just an idea. I could list others.

I still haven't found a way to do this with a local variable, since I can't use _G

UrsaTeddy
April 13th, 2023, 08:07
Okay ... a label that leads to the array indexing clarifies that.

However if the control is something for an end-user you are now relying on them to understand your array structure and indexing strings. Not a user friendly expectation for non-programming types that just use FGU to facilitate game play.

But at least that clarifies what you are intending.

Xarxus
April 13th, 2023, 10:39
Okay ... a label that leads to the array indexing clarifies that.

However if the control is something for an end-user you are now relying on them to understand your array structure and indexing strings. Not a user friendly expectation for non-programming types that just use FGU to facilitate game play.

But at least that clarifies what you are intending.

I think it's the same thing for any data that a possible label should show. Somehow the encoding
needs to know the name of the string to display (e.g. using textres), unless you display a constant.

UrsaTeddy
April 14th, 2023, 00:51
Just a note, I am assuming that the code you posted is testing code. You need to put in a check if the index is valid to cover for misspelled indices.

Right now you are making an assumption that the index is 100% correct and cannot be a nil value. What happens if it is a nil value? Or not a correct index.

Xarxus
April 14th, 2023, 10:07
Just a note, I am assuming that the code you posted is testing code. You need to put in a check if the index is valid to cover for misspelled indices.

Right now you are making an assumption that the index is 100% correct and cannot be a nil value. What happens if it is a nil value? Or not a correct index.

Yes, it's a test code. Thank you for your suggestion.