Hi everyone!
When I was learning love2d from a tutorial, the recommended way to iterate a list and remove objects was to add them to a temporary list "to remove". In the end of the iteration, we iterate the "to remove" list and remove them in the main list. This was a solution presented to avoid conflicts of removing objects while iterating, and I've been using it since then (iterating using ipairs). But is this the recommend way to do this?
I'm having some strange bugs, very rarely, were it seems 2 objects are being removed at the same time, I suspect the problem might be somewhere in this process.
How do you do it?
thanks
Best way to iterate and remove
Re: Best way to iterate and remove
There are two issues with removing multiple items from a list.
1) After each removal, the following items get resorted, to leave no gap in the list. So if you want to delete items 1 and 2 from a list, then after deleting no 1, the former no 2 becomes no 1. So a straight forward iteration would actually remove the first and the third items. To prevent that, you can simply iterate over the list backwards.
2) Each time, one element gets removed, all following items are sorted again. That takes time. So if you remove many items and know it in advance, then instead of going "remove, sort, remove, sort, remove, sort ..." you can save time by going "remove,remove,remove,..., sort" and only sort once in the end. This method is slightly faster, but takes a bit more effort in implementation. You can probably find a working implementation somewhere on the web.
I believe your issue is more related to the first points and unless you have really many items, I wouldn't bother about the second point.
1) After each removal, the following items get resorted, to leave no gap in the list. So if you want to delete items 1 and 2 from a list, then after deleting no 1, the former no 2 becomes no 1. So a straight forward iteration would actually remove the first and the third items. To prevent that, you can simply iterate over the list backwards.
2) Each time, one element gets removed, all following items are sorted again. That takes time. So if you remove many items and know it in advance, then instead of going "remove, sort, remove, sort, remove, sort ..." you can save time by going "remove,remove,remove,..., sort" and only sort once in the end. This method is slightly faster, but takes a bit more effort in implementation. You can probably find a working implementation somewhere on the web.
I believe your issue is more related to the first points and unless you have really many items, I wouldn't bother about the second point.
Check out my blog on gamedev
- kikito
- Inner party member
- Posts: 3153
- Joined: Sat Oct 03, 2009 5:22 pm
- Location: Madrid, Spain
- Contact:
Re: Best way to iterate and remove
Micha means doing this:micha wrote: To prevent that, you can simply iterate over the list backwards.
Code: Select all
local function remove_items(tbl)
for i=#tbl,1,-1 do -- i starts at the end, and goes "down"
if should_be_removed(tbl[i]) then
table.remove(tbl, i)
end
end
end
When I write def I mean function.
Re: Best way to iterate and remove
Hi Micha, thanks for the reply!
Yes, I understood the issue in 1 was the reason the tutorial suggested to use a temporary list to hold the objects to remove. But I didnt understand, from your reply, if this solves it or not.
here's a small sample:
it uses the index to remove, so maybe the problem persists, right?
Yes, I understood the issue in 1 was the reason the tutorial suggested to use a temporary list to hold the objects to remove. But I didnt understand, from your reply, if this solves it or not.
here's a small sample:
Code: Select all
for k,v in ipairs(smoke) do
if v.time >=v.life then
table.insert(remSmoke,k)
end
end
for k,v in ipairs(remSmoke) do
table.remove(smoke,v)
end
Re: Best way to iterate and remove
Hi Kikito,kikito wrote:Micha means doing this:micha wrote: To prevent that, you can simply iterate over the list backwards.
Code: Select all
local function remove_items(tbl) for i=#tbl,1,-1 do -- i starts at the end, and goes "down" if should_be_removed(tbl[i]) then table.remove(tbl, i) end end end
Thanks, so I will replace my remove iterations with that!
- Robin
- The Omniscient
- Posts: 6506
- Joined: Fri Feb 20, 2009 4:29 pm
- Location: The Netherlands
- Contact:
Re: Best way to iterate and remove
Note that it generally is much faster to do this:
Code: Select all
local function remove_items(tbl, should_be_removed)
for i=#should_be_removed,1,-1 do -- i starts at the end, and goes "down"
table.remove(tbl, should_be_removed[i])
end
end
Help us help you: attach a .love.
- kikito
- Inner party member
- Posts: 3153
- Joined: Sat Oct 03, 2009 5:22 pm
- Location: Madrid, Spain
- Contact:
Re: Best way to iterate and remove
That is true only if you already have the should_be_removed table. If you have to produce it from tbl and then remove the elements, then the version I proposed is faster (same number of ifs and deletions, but less additions and one less intermediate table).Robin wrote:Note that it generally is much faster to do this: ...
When I write def I mean function.
- Robin
- The Omniscient
- Posts: 6506
- Joined: Fri Feb 20, 2009 4:29 pm
- Location: The Netherlands
- Contact:
Re: Best way to iterate and remove
Oh, yeah. I thought it was a table you where using, not a function. My mistake!
Help us help you: attach a .love.
Re: Best way to iterate and remove
Not an answer to your question, but still good to know: If your table is not a list (i.e. does not have numeric indices), you can savely remove (but not add) items while iterating with pairs():
Code: Select all
for k,v in pairs(tbl) do
if should_remove(v,k) then
tbl[k] = nil
end
end
Re: Best way to iterate and remove
Could you explain this? I understand that pairs is stochastic in its iteration patterns, but how does this result in the safe removal of elements? Is the table buffered before the loop body begins execution?vrld wrote:Not an answer to your question, but still good to know: If your table is not a list (i.e. does not have numeric indices), you can savely remove (but not add) items while iterating with pairs():Code: Select all
for k,v in pairs(tbl) do if should_remove(v,k) then tbl[k] = nil end end
Do you recognise when the world won't stop for you? Or when the days don't care what you've got to do? When the weight's too tough to lift up, what do you? Don't let them choose for you, that's on you.
Who is online
Users browsing this forum: Google [Bot], Semrush [Bot] and 1 guest