Reputation:
Very often I need something like that:
foreach (Line line in lines)
{
if (line.FullfilsCertainConditions())
{
lines.Remove(line)
}
}
This does not work, because I always get a InvalidOperationException
because the Enumerator was changed during the loop.
So I changed all my loops of this kind to the following:
List<Line> remove = new List<Line>();
foreach (Line line in lines)
{
if (line.FullfilsCertainConditions())
{
remove.Add(line)
}
}
foreach (Line line in remove) {
{
lines.Remove(line);
}
I'm not sure if this is really the best way since in the worst case I have to iterate 2 times over the original list and so it needs time 2n instead of n.
Is there a better way to do this?
EDIT:
I was able to do that using Mark's answer!But what if my collection doesn't implements RemoveAll()?
For example a
System.Windows.Controls.UIElementCollection
EDIT 2:
Again with the help of Mark I'm now able to make the following call to remove all ScatterViewItems:
CollectionUtils.RemoveAll(manager.getWindow().IconDisplay.Items, elem => elem.GetType() == typeof(ScatterViewItem));
Upvotes: 12
Views: 7725
Reputation:
Also you can just use while loop.
int i = 0;
while(i < lines.Count)
{
if (lines[i].FullfilsCertainConditions())
{
lines.RemoveAt(i);
}
else {i++;}
}
Upvotes: 1
Reputation: 1063338
This is baked directly into List<T>
:
lines.RemoveAll(line => line.FullfilsCertainConditions());
or in C# 2.0:
lines.RemoveAll(delegate(Line line) {
return line.FullfilsCertainConditions();
});
In the non-List<T>
case (your edit to the question), you could wrap this something like below (untested):
static class CollectionUtils
{
public static void RemoveAll<T>(IList<T> list, Predicate<T> predicate)
{
int count = list.Count;
while (count-- > 0)
{
if (predicate(list[count])) list.RemoveAt(count);
}
}
public static void RemoveAll(IList list, Predicate<object> predicate)
{
int count = list.Count;
while (count-- > 0)
{
if (predicate(list[count])) list.RemoveAt(count);
}
}
}
Since UIElementCollection
implements the (non-generic) IList
this should work. And quite conveniently, with C# 3.0 you can add a this
before IList
/ IList<T>
and have it as an extension method. The only subtlety is that the parameter to the anon-method will be object
, so you'll need to cast it away.
Upvotes: 17
Reputation: 4082
Build a new list instaed:
public IList<Line> GetListWithoutFullfilsCertainConditions(IList<Line> fullList)
{
IList<Line> resultList = new List<Line>(fullList.Count);
foreach (Line line in fullList)
{
if (!line.FullfilsCertainConditions())
{
resultList.Add(line)
}
}
return resultList;
}
Upvotes: 1
Reputation: 3548
You could simply replace original list with filtered one:
lines = lines.Where(line => line.FullfilsCertainConditions()).ToList();
Upvotes: 1