What way do you use to remove items from list when using for n = 0 to last
Posted: Tue Jun 17, 2025 10:52 am
A typical problem I am facing in my coding is something similar to these two examples (same thing twice, but with foreach and for-next both shown):
Notice that For-Next version has additional problem, as when item is removed in middle of for-next loop, then when going to the last n value, the list[n] doesnt exist anymore.
Basically I solve this problem by using RemoveList, wich is executed afterwards:
Do notice the step -1 in the removal for-next loop, point being that as I am adding the RemovedItems in order, they need to be executed in opposite order, as from last to first, since if I remove the first Item first, then the second Item will change its location, and I would be removing a wrong Item.
This, however, isnt perfect yet.
First of all, quite often I am in situation where the table has Functions to execute inside them.
Problem is that, first of all, it is this executable which will decide if item is to be removed or not, and another problem is that only solution that I have been able to think is one where the executin happens after the loop which checks them, while it would be much handier to do the execution inside the loop.
To demonstrate it a bit:
This would be the ideal way to handle it, right when it sees in the list that it is to be executed, it would execute it.
However, since that execution might result in a removal of the item (or even addition of another), it cant be done there in the middle, but I have to postpone the execution to a later point:
But now if this executable results in destroying the item, I need to have some system to know which item to destroy from the list.
So far only way I have been able to figure out, is to use UniqueID value for each item, as in instead of:
{Execute=True, Func=Func1}, I will have {Execute=True, Func=Func1, UniqueID=GetUniqueID()}
because this way, if after execution it is decided that an item needs to be destroyed, I can add the UniqueID to the list, and using this I can find the right Item from the list to be destroyed, even if that Items location has changed, either due to removal of another item, or more items added to the list as a result of the execute func.
Naturally this removal needs to be done outside the for-next loop, or it might result in error when n would become higher than the amount of items left on the list.
Here is a working example:
What I would like to do, is practically following:
As in whole thing would be handled during one for-next (of foreach) loop, but I dont think that is doable.
What ways have you others used to handle this kind of situation, or is my current way of using UniqueID variable for correct identification at removal, and doing both execution and removal outside the for-loop the only way to do it?
Code: Select all
list = {0, 1, 2, 3, 4, 5}
DebugPrint("ForEach")
ForEach(list, Function(ID, value)
DebugPrint(ID..": "..value)
If value=3 Then RemoveItem(list, 3)
EndFunction)
list = {0, 1, 2, 3, 4, 5}
DebugPrint("For-Next")
For n = 0 To TableItems(list)-1
DebugPrint(n..": "..list[n])
If list[n] = 3 Then RemoveItem(list, n)
NextBasically I solve this problem by using RemoveList, wich is executed afterwards:
Code: Select all
list = {0, 1, 2, 3, 4, 5}
DebugPrint("For-Next")
Local ToBeRemoved = {}
For n = 0 To TableItems(list)-1
DebugPrint(n..": "..list[n])
If list[n] = 1 Then InsertItem(ToBeRemoved, n)
If list[n] = 3 Then InsertItem(ToBeRemoved, n)
Next
For n=TableItems(ToBeRemoved)-1 To 0 Step-1
RemoveItem(List, ToBeRemoved[n])
Next
DebugPrint("After Removal")
For n=0 To TableItems(list)-1
DebugPrint(n..": "..list[n])
Next
This, however, isnt perfect yet.
First of all, quite often I am in situation where the table has Functions to execute inside them.
Problem is that, first of all, it is this executable which will decide if item is to be removed or not, and another problem is that only solution that I have been able to think is one where the executin happens after the loop which checks them, while it would be much handier to do the execution inside the loop.
To demonstrate it a bit:
Code: Select all
list = { {execute=True, Func=Func1}, {Execute=False, Func=Func2}, {Execute=False, Func=Func3}, {Execute=True, Func=Func4}, {Execute=False, Func=Func5}
For n = 0 To TableItems(list)-1
If list[n].Execute = True Then List[n].Func()
Next
However, since that execution might result in a removal of the item (or even addition of another), it cant be done there in the middle, but I have to postpone the execution to a later point:
Code: Select all
list = { {execute=True, Func=Func1}, {Execute=False, Func=Func2}, {Execute=False, Func=Func3}, {Execute=True, Func=Func4}, {Execute=False, Func=Func5}
Local ToBeExecuted = {}
For n = 0 To TableItems(list)-1
If list[n].Execute = True Then InsertItem(ToBeExecuted, list[n].func)
Next
For n = 0 To TableItems(ToBeExecuted)
ToBeExecuted[n]()
Next
So far only way I have been able to figure out, is to use UniqueID value for each item, as in instead of:
{Execute=True, Func=Func1}, I will have {Execute=True, Func=Func1, UniqueID=GetUniqueID()}
because this way, if after execution it is decided that an item needs to be destroyed, I can add the UniqueID to the list, and using this I can find the right Item from the list to be destroyed, even if that Items location has changed, either due to removal of another item, or more items added to the list as a result of the execute func.
Naturally this removal needs to be done outside the for-next loop, or it might result in error when n would become higher than the amount of items left on the list.
Here is a working example:
Code: Select all
UniqueID = 0
Function GetUniqueID()
UniqueID = UniqueID + 1
Return("Unique"..UniqueID)
EndFunction
Function MyRemoveItem(UniqueID, list)
Local IDToRemove = -1
For Local n = 0 To TableItems(list)-1
If UniqueID = list[n].UniqueID Then IDToRemove = n
Next
If IDToRemove > -1 Then RemoveItem(List, IDToremove)
EndFunction
Function FuncTrue()
Return(True)
EndFunction
Function FuncFalse()
Return(False)
EndFunction
Func1 = FuncFalse
Func2 = FuncTrue
Func3 = FuncTrue
Func4 = FuncTrue
Func5 = FuncFalse
list = { {UniqueID=GetUniqueID(), execute=True, Func=Func1}, {UniqueID=GetUniqueID(), Execute=True, Func=Func2}, {UniqueID=GetUniqueID(), Execute=False, Func=Func3}, {UniqueID=GetUniqueID(), Execute=True, Func=Func4}, {UniqueID=GetUniqueID(), Execute=False, Func=Func5} }
DebugPrint("list")
For Local n = 0 To TableItems(list)-1
DebugPrint(n.." - UniqueID:"..list[n].UniqueID)
Next
Local ToBeExecuted = {}
For Local n = 0 To TableItems(list)-1
If list[n].Execute = True Then InsertItem(ToBeExecuted, CopyTable(list[n]))
Next
For Local n = 0 To TableItems(ToBeExecuted)-1
Local Remove = ToBeExecuted[n].func()
If Remove=True Then MyRemoveItem(ToBeExecuted[n].UniqueID, list)
Next
DebugPrint("list after execution")
For Local n = 0 To TableItems(list)-1
DebugPrint(n.." - UniqueID:"..list[n].UniqueID)
Next
Code: Select all
For n=0 to tableitems(list)-1
if list.execute=true
local Remove=list.func()
if Remove = True then removeItem(list, n)
endif
nextWhat ways have you others used to handle this kind of situation, or is my current way of using UniqueID variable for correct identification at removal, and doing both execution and removal outside the for-loop the only way to do it?