Array list RemoveAt

I want to clean a list of lines where I have some overlapping lines. I wrote it as below.
But after remove at an index, the list Count remain the same as previous.
which is causing out of range error message.

Please some one let me know , why it is not working.
Please read below. Why jl value is going out of range, after removing one element from the same list.
The List.Count should be updated automatically after RemoveAt an Index… NO?

public void clean_up_lines(List lines_pro1, out List lines_pro)
{
for (int jl = 0; jl < lines_pro1.Count; jl++)
{ int cnt_n = 0;
for (int jk = 0; jk < lines_pro1.Count; jk++)
{

                   if (jl != jk)
                   {
                       if (((lines_pro1[jl].From == lines_pro1[jk].From) &&
                           (lines_pro1[jl].To == lines_pro1[jk].To)) ||
                           ((lines_pro1[jl].To == lines_pro1[jk].From) &&
                           (lines_pro1[jl].From == lines_pro1[jk].To)) ||
                            ((lines_pro1[jl].From == lines_pro1[jk].To) &&
                           (lines_pro1[jl].To == lines_pro1[jk].From))
                           )
                       {
                           lines_pro1.RemoveAt(jk);
                          
                           cnt_n = cnt_n + 1;

                       }

                   }

               }



           }
         
           lines_pro= lines_pro1;
    



       }

I think its best to create a new list were you add the lines you want to keep and dispose the old lists after the checks… this way you still keep the new lines.

Your way is not working because you change the lines_pro1.count… if the list is 25 long and its at range 15 and should go to 16 but you removed 15. Should it skip 15 or continue with 16? Thats why its giving an error. To solve this use the way I described above or create a list where you store the jk’s to remove and remove them all afterwards.

Or check this link:

It’s just not allowed to change a list when your looping through it.

-Jordy

1 Like

Hi,

I think that your problem is that you are removing elements of an array while you are in the “for loop” for that array. Once you are inside the “for loop” you cannot change the limit (jl<lines_pro1.Count) and that is why when a single element is removed you immediately go out of range.

There are several solutions (depending on the problem). One solution is, while you are in the loop, to make an array of positions (int) of lines in the array that you want to remove…lets call it “toremove”…and then when you have this list of elements to be removed you make a copy of the original array…BUT…you do this in a loop and while you are making the copy, for each element you check if it is on your “toremove” list…if it is not then do not copy…and that is it. You end up with a new array that has only the elements you want, and you can delete the old array.

(There is an easier solution but it works with two different arrays…in your case you are comparing one array with itself so it is a bit more complicated)

Greetings,
Milos Dimcic
Dr.-Ing.
www.programmingarchitecture.com

1 Like

It is, I think, because the count is stored when you first enter the for loop. It is never a good idea to modify the list while you are iterating it. There are two ways to do this, the first is to store the indices that you want to remove, then remove them in a separate step. Or you can use LINQ Distinct statement with a custom comparator.

// strategy 1
    List<Line> lines_pro1 = new List<Line>(); // defined elsewhere
    List<int> toRemove = new List<int>();
    for (int jl = 0; jl < lines_pro1.Count; ++jl)
    {
        for (int jk = jl + 1; jk < lines_pro1.Count; ++jk)
        {
            if (((lines_pro1[jl].From == lines_pro1[jk].From) &&
                    (lines_pro1[jl].To == lines_pro1[jk].To)) ||
                ((lines_pro1[jl].To == lines_pro1[jk].From) &&
                    (lines_pro1[jl].From == lines_pro1[jk].To)) ||
                ((lines_pro1[jl].From == lines_pro1[jk].To) &&
                    (lines_pro1[jl].To == lines_pro1[jk].From))
                )
            {
                toRemove.Add(jk);
            }
        }
    }
    // run backwards through toRemove so that the indices in toRemove 
    // are always valid while objects are being removed from the list
    for (int i = toRemove.Count - 1; i >= 0; --i)
    {
        lines_pro1.RemoveAt(toRemove[i]);
    }

    // strategy 2 
    IEqualityComparer<Line> lineComp = new LineComparer();
    List<Line> unique = lines_pro1.Distinct(lineComp).ToList();

}

private class LineComparer : IEqualityComparer<Line>
{
    public bool Equals(Line x, Line y)
    {
        return ((x.From == y.From) && (x.To == y.To)) ||
                ((x.To == y.From) && (x.From == y.To)) ||
                ((x.From == y.To) && (x.To == y.From));
    }

    public int GetHashCode(Line obj)
    {
        return obj.GetHashCode();
    }
}        
1 Like

Thanks to every one ! I was assuming I should not remove element while inside a loop and now I am sure why it is gone wrong.

Many Many thanks again !

Many Thanks Menno, for the solution you gave to the problem. Yes I totally forgot to use just a bool check :smiley:

The last thing to say is that it can be “dangerous” to compare floating point numbers or Point3d values with the == operator. It is more safe to compare them within tolerance using the EpsilonEquals function:

Point3d p = new Point3d(1e-10,0,0);
Point3d p2 = new Point3d (0,0,0);

bool exactlyEqual = p == p2; // will be false;
bool approximatelyEqual = p.EpsilonEquals(p2, 1e-6); // will be true

Hi Menno, Thanks ! I was not saying to use bool in this way.
But thanks again !