So, I’m making a game module for a project I’m working on, and for some reason table.find(table, value) doesn’t work to return the index of the value when the index is not 1 (there are 24 total indexes).
The problematic function is this:
GameModule.RemoveTribute = function(self: typeof(GameModule), player: Player)
for i, v in self.TributesTable do
print(i, v.Name)
end
local tributeIndex = table.find(self.TributesTable, player)
if tributeIndex then
self.TributesTable[tributeIndex] = nil
return tributeIndex
end
end
and the function that initializes the table is this:
GameModule.new = function()
local self = setmetatable({}, GameModule)
self.TributesTable = table.create(24)
self.InSession = false
return self
end
Does table.find() bug out when there are 23 nil indexes and you are attemping to table.find() on an index that is > 1?
I did the for loop to make sure I wasn’t going crazy and that the index doesn’t exist, but it does…
This is what it prints (it’s fired to a local script, but i’m printing to ensure the index is valid before doing anything)
yet it works entirely fine with the index as 1;
I looked at the Roblox Documentation to see if there was any information on the behavior for table.find() in Luau, but there’s… nothing? It doesn’t make sense. Does anyone have any insight on this and has a suggestion for what I should try?
I think the 23 nil indexes you mentioned might be your culprit.
Luau is treating the table as a dictionary, even though it has number indexes.
The way Luau determines an array is consecutive, ascending indexes starting from one. As soon as that chain is broken, the rest of the table is treated as a dictionary.
Hence, 23 indexes will break that chain provided there are not valid consecutive indexes starting from 0. The solution is to make sure table elements are shifted to close gaps when not in use, for example using table.remove.
Hm, okay. That’s strange. I could do a for loop, I just wish that it would have worked in a much simpler, prettier manner.
Thank you! I’ll keep this open in case anyone has some form of workaround I could possibly work with (and if not, then oh well. I can live with it)
if you want a workaround, you could just give it a separate method to implement iteration logic. table.find will still work on the array part of the table if you wanted it to anyway.
function myTable.getkey(value: any)
for k, v in myTable do
if (v == value) then return k end
end
end
(if the table is large, you could use a different searching algorithm)
find = function(table, query)
for key, value in table do
if value == query then
return key
end
end
return nil
end
local tbl = {
[1] = 2,
[2] = 4,
[4] = 8,
[8] = 16
}
print(find(tbl, 2)) -- 1
print(find(tbl, 4)) -- 2
print(find(tbl, 8)) -- 4
print(find(tbl, 16)) -- 8
could work then
edit: i just realized you already posted a better version of this but whatever
That works. I think that’d probably be the most memory efficient that is feasible with table.find().
If I feel it uses too much memory (which, luckily for me, this is server-sided), I can always do the for loop iteration, it just feels less clean than being able to do table.find().
Is there any particular reason you can’t just leave the keys removed from the table and have other elements shifted down? remember there is an overloaded version of table.insert which can insert at a specific index, and would likely be more efficient.
it is specifically necessary, yes, because it is intended to be a queue where players can be randomly inserted from any index between 1 and 24. thus, if there is an index at 7, it is not necessarily true that indexes 1-6 are also filled.
and the index refers to a position (it’s less of a position in the queue and more an identifier i need). for example, if someone has a Tribute Number of 23, they must be in District 12, tribute 1. So, if I were to attempt to shift it to index 7, it would be District 4, tribute 1 (which was not queried)
in that case, @idealcrime’s solution would probably be best. However, you might want to use false as the value, because it’s a falsy value and won’t allow the key to get gc’d. Then, you can literally just write if not tbl[key] then instead of if tbl[key] ~= 0 then.
Do you have any clue how many bytes each use? I’m aware false and true are technically stored as 1 and 0, but also numbers are stored as doubles, so they take up 8 bytes each (and that therefore uses something like 192 bytes to store 24 0 values.
If not, I’ll just happily look it up to see which one would be best memory-wise (if either)
true and false actually take up 1 byte each… sorry no need to correct that lol
0 is still a number, so is still a double. Keep in mind Luau functions tend to be very lightweight, so if you’re concerned about memory you could use my algorithmic approach. However, then again, this will be tiny micro-optimisations, so it won’t impact performance that much which you use.