Generally iterating over a seq and deleting elements does not work. Nim gives a warning when length of seq changes while we iterate over it with a for loop. There exist situations where we have to process elements of seq and conditional have to delete them from the list. In this case a plain filter template does not work. C++ example:
void QuickhullDisk::remove_pre_and_post_apex_disks_and_contained_disks_in_one_of_the_two_from_candidate_apex_disks_if_exist(
CircularDisk2D* preApexDisk_dp, CircularDisk2D* postApexDisk_dq,
list<pair<Point2D, CircularDisk2D*>>& candidateTriangleApexNDiskPairs, list<CircularDisk2D*>& containedDisksInPreOrPostApexDisk) const
{
list<pair<Point2D, CircularDisk2D*>>::const_iterator it_TriangleApexNDisk = candidateTriangleApexNDiskPairs.begin();
while (it_TriangleApexNDisk != candidateTriangleApexNDiskPairs.end())
{
CircularDisk2D* candidateApexDisk = (*it_TriangleApexNDisk).second;
if (candidateApexDisk == preApexDisk_dp || candidateApexDisk == postApexDisk_dq)
{
it_TriangleApexNDisk = candidateTriangleApexNDiskPairs.erase(it_TriangleApexNDisk);
continue;
}
if (preApexDisk_dp->contain(*candidateApexDisk, _resNeg6) || postApexDisk_dq->contain(*candidateApexDisk, _resNeg6))
{
containedDisksInPreOrPostApexDisk.push_back(candidateApexDisk);
it_TriangleApexNDisk = candidateTriangleApexNDiskPairs.erase(it_TriangleApexNDisk);
}
else
{
++it_TriangleApexNDisk;
}
}
}
The C++ iterator works because erase() returns the next iterator. For this example there is not only deletion of elements involved, as the line "containedDisksInPreOrPostApexDisk.push_back(candidateApexDisk);" does an additional action. So I assume that a filter template may not work. How do we such operations in Nim best?
When there was no iterators (e.g. C) or not that popular in the past. It is usually done by keeping two index and scan. This keeps the elements' order (stable).
var xs = @[1,2,3,4]
var i,j = 0
while j < xs.len:
# check xs[j]
if xs[j] mod 2 == 0:
# to keep
xs[i] = xs[j]
i.inc
j.inc
xs.setLen(i)
assert xs == @[2,4]