So if I have a table, and I want to add instances to it that can already be in that table, how do I check if the table does contain them already, resulting in not adding them there? I know I could loop through the table and check if the instance I want to add is the instance I am looping through, but that does not seem very performant mainly when there are a lot of instances in the table. So what is the most performant way to check for instance in a table?
You can use table.find to search through the table and find specific value
If you want to check if an instance is in a table you can do this:
local instances = {}
local instance = ...
if table.find(instances, instance) then
-- Instance is in the table "instances"
end
This function also searches through each value in the table though, I’m not sure if it can be done more efficiently unless the table was setup in some weird way. Performance also depends on how large the table is and how frequently you are going to be using table.find
Well, how do you want to find something without looking for it? If you want to bypass searching, you have to, when you add an instance to a table, give this instance an attribute or a tag. “AlreadyInTheTable” for example! The second time you add it, you just have to query that instance for that attribute or tag. And then you just need to remove that attribute/tag when you remove the instance from the table. At least that’s one solution I can think of right now.
Adding onto @Orbular3’s solution, you should use classical dictionary optimizations, which is probably what he referred to as “weird setup”. It isn’t weird, in fact, it’s a common optimization method, used in many interview questions too. I’ve written more about it here. The optimization basically says that, if the table is only used for checking if something is in that table, then you can move the values to the keys, which is more performant. As a much easier to understand example, instead of doing this:
local some_table = {
someinstance1,
someinstance2,
someinstance3
}
table.insert(some_table, someinstance4) --Inserting
if table.find(some_table, someinstance5) then --Checking
end
--Checking traverses the entire table, each instance, one by one...
You can move the instances to the keys, and that way, you just index the table, and you either get true
or nil
!
local some_table = {
[someinstance1] = true, --true marks its existence
[someinstance2] = true,
[someinstance3] = true
}
some_table[someinstance4] = true --Inserting (we set it to true to mark its existence)
if some_table[someinstance5] then --Checking
end
--Checking is done instantly now!
Alternatively, try @Dev_OnCake’s solution, but I personally don’t recommend using attributes since they over-complicate things. In fact, instances also make code flow more complicated, so there might be a bigger and much better alternative to the current system you use. This complexity is subjective but I experienced it with one of my games and it wasn’t good.
But this depends on instance’s name, not on instance itself (or atleast I think) The instances I am checking for all have same name, which results (or atleast according to my test I just did) in always returning true if there is only one instance with the same name
It doesn’t depend on the instance’s name. I think that tables are implemented using hash tables, which basically means that keys are “hashed” into an integer and then “stored” as an array index. They have got nothing to do with what the name of an instance is. I don’t even think that userdata like instances are hashed - I’m pretty sure that the memory address in which they are stored is taken and then the division/mod stuff.
At least, it shouldn’t - don’t use the names of the instances as the keys, use the instance itself, just in case you’ve done that.
nevermind I am just messed up
By the way I didn’t really solve it, I just recommended an optimization, so the solution should be @Orbular3’s reply. I hope that random people having the same problem see this optimization though, it’s a pretty important one
I read your post where you compare the performance between arrays and dictionaries and I am a bit surprised! I haven’t really read up on this topic before because I’ve never had a performance problem with tables, but always thought that arrays were faster because you just have an index with an associated value. Thanks for the hint and the proof in the script.
one more thing: Is there a way to get the instance ITSELF from this dictionary? Because as of now, I am only able to get the true or nil value. According to your explenation, this dicionary can be used only to check for the key, so should I make another dictionary that would simply be used to acces the instance I need and this dictionary would only manage when and when not to add instance in this second dictionary?
You index it with the instance itself? Don’t you have it already?
If you’re looping, use the first thing the iterator returned by pairs
returns. So, in this case:
for k, v in pairs(t) do
--imagine some code here
end
k
would be the instance.
If the index is relevant, you can use an array or even better, you can use two tables like you said.
Oh I didn’t realise that! I am sorry this is like my second time using dictionaries instead of simple tables, so I am little confused