Access Table From Value

Is it possible to do the following, or something similar?

local tbl = {
    'hello',
    9,
    true
}
local value = tbl[1]
print(value.tableParent) -- Outputs: {'hello', 9, true}

I highly doubt this is possible the way I portrayed it (as a property).


I need this for a scenario in which I do not have the table, but a class that is part of that table.

I don’t quite understand what your trying to do. The code you provided would error since the table is an array, so value would point to the string “hello” and not a table, so you’d get a key error when you try to call value.tableParent.

Let’s say I didn’t know what tbl was, but that specific 'hello' string was part of it. I am trying to get tbl from that 'hello' string.

Again, I do not believe this is possible.

Yeah not possible to get the entire array from a value in the array unless the value was a duplicate of the array I guess.

1 Like

Tbh, there should be method for this. Like:

table.getArrays(value)

local a = 'hello' -- this has a specific memory address
local b = 'hello' -- this has a different memory address

local tbl = {a, 'hi there'}

print(table.getArrays(a)) -- Prints: {{'hello', 'hi there'}}
print(table.getArrays(b)) -- Prints: {}

The reason they don’t is because an array just stores stuff. It’s like a shelf with a bunch of unlabeled boxes on it. You can open the first box to find pencils inside, and then the second to find paper, but none of the boxes will contain a list of what’s on the shelf unless you put it in there.

1 Like

I’m not sure whether this specifically will work for you since I don’t know your exact implementation, but the basic principle is that you can wrap every value of the array into objects that hold a reference to the parent array; something like this:

-- this actually won't work since tbl is nil, but I'm trying to show you how the table will look like
-- I will show you later in this post how to make this work
local tbl
tbl = {
    {value = 'hello', tableParent = tbl}, -- "wrap" the original value into an object
    {value = 9, tableParent = tbl},
    {value = true, tableParent = tbl}
}

local obj = tbl[1]
print(obj.value) -- Outputs: 'hello'

-- these print the same table
print(tbl)
print(obj.tableParent)

Now we just need to set up every table like this. We need to account for two scenarios: converting a normal table and adding new values to a table.

Converting a normal table

Basically just a function that takes an existing array and replaces the values with objects.

local function convertArr(arr)
    for i, v in ipairs(arr) do
        arr[i] = {value = v, tableParent = arr}
    end
    return arr
end

Using this method, you can call convertArr on new tables directly:

local tbl = convertArr({
    'hello',
    9,
    true
})

local obj = tbl[1]
print(obj.value) -- Outputs: 'hello'

-- these print the same thing
print(tbl)
print(obj.tableParent)

Or pass an already existing table like so:

local tbl = {
    'hello',
    9,
    true
}
convertArr(tbl) -- this achieves the same thing as the above example (tbl is passed by reference)
Adding new values to the table

This is needed if you plan on adding values to a table after it’s initialized. This is easiest with a metatable:

local mt = {
	__newindex = function(arr, index, val)
		rawset(arr, index, {value = val, tableParent = arr})
	end
}

We can do this now:

local tbl = convertArr({
    'hello',
    9,
    true
})
setmetatable(tbl, mt)

tbl[4] = "new value" -- the __newindex metamethod creates the wrapper object for us

local obj = tbl[4]
print(obj.value) -- Outputs: "new value"

-- this still works the same way it did before
print(tbl)
print(obj.tableParent)

The catch

Toggle

Keep in mind that if you want to modify a table like this, you’ll have to modify the value field of the object:

tbl[1].value = "goodbye"

Fortunately, we can create another function to make this easier (mutator function):

local function modifyValue(arr, index, val)
    arr[index].value = val
end

Sidenote (which might actually be the solution, idek)

Toggle

This is also something you might be able to create on your own. Something kind of like this:

local function add(arr, obj) -- this could be in a module instead
    table.insert(arr, obj)
    table.insert(obj.arrays, arr)
end

Since you’re using classes of your own you could perhaps add an arrays field to them that stores references to all the arrays they are in. You then of course create your own getArrays method which simply returns the arrays field.

2 Likes

Thanks for this! I’ll try to implement your closing bit into my module.