table.indexOfElement not finding my element

,

Hi, getting some really weird behaviour which may be a Lua thing...?

I'm finding the index of a int value in a table using:

if indexOf(self.levelAvailable, self.cursorCoord) then
    -- do something
    self.levelAvailable[index] = nil
end

However, sometimes it just doesnt find it...I'm making a grid based sokoban type game and there are 4 or so available tiles and most of the time it fails to find them after a few have been set.

so did some more searching and found also tried

table.remove(tbl, index)

and this worked, so i wonder if playdate is doing something different under the hood to make setting to nil unacceptable in this case?

table.remove will shift all other values to fill in the empty space, this will keep the table as a sequence.

table[key] = nil will remove the value at the key, but it will not shift the remaining values. So you will have a 'hole' in the table.

if you're using the table like an array, where you are indexing into each key, you want to use table.remove

I guess that means array like and object like tables are different under the hood?

I don't know a whole lot about the implementation details of Lua. But the documentation for tables seems to indicate that lua doesn't care if a table is a sequence or not. Lua Manual 5.4 Values & Types
It points to the length operator which is only available on a table if it's a sequence, offers a more in-depth answer about how lua works if you're treating a table like an array. (Which it looks like you might be?)
https://www.lua.org/manual/5.4/manual.html#3.4.7

Is cursorCoord an integer or a table? If it's a table (e.g. vector) you're comparing table ids instead of their values. It's also completely possible that table.indexOfElement stops when it hits nil. I guess that case would qualify as an SDK bug.

Generally speaking there are no arrays in the Lua language and an array-like table simply contains integer keys 1..N. Under the hood Lua does all sorts of optimization tricks and even uses actual C arrays, but you don't really need to care about those. In Lua you're always working with tables that are like objects or dictionaries in other languages.

1 Like

Yes self.cursorCoord is an int. I was expecting the index of value to still work well enough if there was a table (array) of values, where most have been set to nil bar one or two, this is not teh case it seems... which is fine. table.remove works, just odd.

Overthinkig what does it even mean to find index of element in a table :melting_face:

The type table implements associative arrays, that is arrays that can be indexed not only with numbers, but also with strings or other values.

Regardless of key type any key associated to the value nil is not considered to be part of the table. It is an absent key. But there are different ways to iterate over absent keys of different types.

Indexed Array Associative Array (Hash Map)
Keys Sequential integers (1, 2, 3…)
Arbitrary (strings, numbers, mixed)

tbl[1], tbl[2], tbl[3] tbl["name"], tbl[{1,2}], tbl[3.5]
Iterating with for i = 1, #tbl or ipairs() pairs()

ipairs assumes that table is representing regular indexed array and that it ends just before its first nil element. It will iterate sequentially over the key–value pairs up to the first absent key.

function indexOfElementIPairs(tbl, value)
    for i, v in ipairs(tbl) do
        if v == value then
            return i
        end
    end
    return nil
end

Watch ipairs bailing out after 2nd key

index-of-element-ipairs-crop

With for loop we can iterate numerically from 1 to the length of the table

function indexOfElementFor(tbl, value)
    for i = 1, #tbl do 
        if tbl[i] == value then
            return i
        end
    end
    return nil
end

Length operator applied on a table returns a border - index of an element just before absent key. It doesn't keep track of all absent keys, or all borders. It just looks for any border.

If table has more then one border, it doesn't guarantee to return any specific one.

Here are some tables with 3 borders and length operator being its best non-deterministic self

index-of-element-for-00-crop

index-of-element-for-01-crop

pairs will iterate over all key–value pairs of table, in no particular order, but skipping absent keys

index-of-element-pairs-crop

Moral of the story:

  • arrays are not supposed to contain nil values
  • table.remove() works because its doesn't just delete element but also shifts all of consequent elements to fill the hole in a table
  • use pairs(tbl) to iterate over weird unordered stuff