2

I want to delete all entries from a table, wich equals a given value. Now, I got a pretty little problem one might to know, how to handle.

This is the Code:

function(list_to_search_in, compared_value, invert)
    for k,v in pairs(list_to_search_in) do
        if invert and v ~= compared_value then
            table.remove(list_to_search_in, v)
        if not invert and v == compared_value then
            table.remove(list_to_search_in, v)
         end
    end
end

The Problem:

Let's say the table is { 1, 2, 3, 2 }. So when I'm iterating through that loop and come to the first match, it's removed from the table. This means the value and the key is deleted.

Now the key of the deleten value is assigned to the next value in line. But due the skript will check the value of the next key, this value (whichs kay has been just altered) will never be checked.

I thought, a simple

k = k - 1

after a remove would do the job, but it doesn't.

v = nil

would do great I think, but only if garbage-collector does not do his job in this very moment the pairs iterates to the next value.

Anyone has an idea? I would prefer an text-based hint to a finished syntax which solves the problem.

hjpotter92
  • 78,589
  • 36
  • 144
  • 183
jawo
  • 856
  • 1
  • 8
  • 24
  • 2
    See http://stackoverflow.com/questions/12394841/safely-remove-items-from-an-array-table-while-iterating. In particular, my answer http://stackoverflow.com/a/12397742/107090. – lhf Sep 09 '14 at 12:15
  • So there is no other way, to create a second table? I'm using lua on a microcontroller, not to script games. so performance is a big issue to me. – jawo Sep 09 '14 at 12:16
  • 1
    My answer does not create a second table: it marks items to be deleted and then packs the original table. – lhf Sep 09 '14 at 13:11
  • It looks like you want to manipulate a table with a [sequence](http://www.lua.org/manual/5.2/manual.html#3.4.6) and end up with the same table, still with a sequence. You normally wouldn't use `pairs` for that. – Tom Blodget Sep 10 '14 at 00:53

1 Answers1

1

Don't use table.remove for this. It squeezes the "hole" out of array-like tables. That's not allowed during an iteration using pairs/next. Just set the value to nil.

If you need to squeeze holes out of the table then you can either create a new table and populate it with only the values you want to keep or do the removals during the first pass and then squeeze out holes in a second pass.

Also the order of item traversal when using pairs is not guaranteed in any way.

Etan Reisner
  • 77,877
  • 8
  • 106
  • 148
  • But when the table is really large, isn't it possible, that the carbage collector deletes some of the nil-value-keys during iteration? afaik, one can never know when the collector will do his job, right? – jawo Sep 09 '14 at 11:28
  • biger problem: the table must not contain nil-values – jawo Sep 09 '14 at 11:35
  • Setting a value to `nil` in a Lua table deletes the entry. – Colonel Thirty Two Sep 09 '14 at 13:45
  • 1
    @Sempie No, I don't think there is a gc issue because I don't believe the gc will compact/rehash the table during a traversal. Setting an element to `nil` does not compact/rehash the table but assigning new elements can. – Etan Reisner Sep 09 '14 at 14:41
  • 2
    Etan is correct. From the docs: `The behavior of next [used by pairs] is undefined if, during the traversal, you assign any value to a non-existent field in the table. You may however modify existing fields. In particular, you may clear existing fields.` – Colonel Thirty Two Sep 09 '14 at 16:50
  • @ColonelThirtyTwo That wasn't the question, but is a useful snippet to include anyway, the question was can the gc violate that `next` contract from underneath a traversal. – Etan Reisner Sep 09 '14 at 17:25