How to make it so that you can insert values into the index of a table that doesn't necessarily exist (and if it doesn't, then it creates one)

Ill explain more in detail what I mean since I’m not even sure what to name this post

If you have a table, lets say

local table = {}

If you run table[“Something”] = “Hi” then, even though table[“Something”] doesn’t necessarily exist, it automatically creates table[“Something”] with the value “Hi”

local table = {
          ["Something"] = "Hi"
}

Is there a way to do something like that but instead, with table.insert?

local data = {
 
}
-- keep in mind these lines normally error because data["CollectedStuff"] doesnt exist yet: "invalid argument #1 to insert, table expected got nil"
table.insert(data["CollectedStuff"], thing1) 
table.insert(data["CollectedStuff"], thing2) 

--this becomes:
local data = {
     ["CollectedStuff"] = {thing1, thing2}
}

And if there isn’t one, how would I go about doing it with data[“inserthere”] instead?

1 Like

You’d have to either manually insert the CollectedStuff into the data table prior to the insert like so:

local data = {}

data["CollectedStuff"] = {}
table.insert(data["CollectedStuff"], thing1) 
table.insert(data["CollectedStuff"], thing2)

print(data)
--[[
{
    ["CollectedStuff"] = {thing1, thing2}
}
]]

Or you could make a function to do it for you:

local function insertIntoMember(tbl, name, value)
    local member = tbl[name]

    -- creates the table inside if it doesn't already exist
    if not member then
        member = {}
        tbl[name] = member
    end

    -- if the member is already defined as something that is not a table, error
    if typeof(member) ~= "table" then
        local errorMessage = string.format("Cannot insert into member %s as it is of type %s", name, typeof(member))
        error(errorMessage)
    end

    table.insert(member, value)
end

local data = {}

insertIntoMember(data, "CollectedStuff", thing1)
insertIntoMember(data, "CollectedStuff", thing2)

print(data)
--[[
{
    ["CollectedStuff"] = {thing1, thing2}
}
]]
2 Likes

Note that table.insert is meant for arrays (tables with number keys), not dictionaries [tables with immutable (unchangeable) keys], so you actually shouldn’t be using table.insert in the first place

Prematurely setting an appropriate value (an array type in this case) would be the fix eg. data[“CollectedStuff”] = {} . It isn’t explicitly what you asked for, but it’s how you should do it

2 Likes
if data.CollectedStuff==nil then data.CollectedStuff=table.create(2) end
table.insert(data["CollectedStuff"], thing1) 
table.insert(data["CollectedStuff"], thing2) 
2 Likes
local data = {}
setmetatable(
	data,
	{
		__index = function(_, key)
			local container = {}
			data[key] = container
			return container
		end
	}
)

table.insert(data["CollectedStuff"], thing1) 
table.insert(data["CollectedStuff"], thing2)
1 Like

Metatables is bad for perfomance

1 Like

Yes, but they are the only way to have missing key value pairs added automatically when indexing, which seems to be what OP wants.

But yes, it’s not necessarily a good idea to use metatable magic in this kind of situation. Not only for performance reasons, but also because it can violate the principle of least surprise and unnecessarily make the code more complicated.

What you suggested is probably a more sensible approach although I would write that if statement as a proper code block rather than a one-liner.

Very simply if you do something like this you need to initialize the array if one does not exist.

if data.CollectedStuff==nil then  data.CollectedStuff={} end

if you wanted to created a function within the array to insert data into a key then do it.

2 Likes

Your question is exactly what inserting a value will do if it doesn’t exist, but the array has to exist to do that.

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.