Way to delete row from list if criteria met - c#

i am running two lists through a fuzzy matching program and want to be able to remove that row from the list if a match occurs but am having problems doing so. here is my code
foreach (var name in list)
{
foreach (var stepone in Step1)
{
if (FuzzyMatching(name.Full(), stepone.Full()) >= 90)
{
csvcontent.AppendLine(name.Full());
//find a way to delete list record out of list
//list.Remove(name);
}
}
}

you can mark in another list all the items to delete.
When the loop is finished you can delete all the items in the new created list from that list.
With LINQ is simply:
list1 = list1.Where(x => !itemToDeleteList.Contains(x)).ToList();

You can't remove an item from a list using a ForEach loop. In this case you should use a for loop.
var list = new List<string>();
list.Add("a");
list.Add("b");
list.Add("c");
list.Add("d");
for(int i = 0; i < list.Count(); i++)
{
if(list[i].Contains("a"))
{
list.RemoveAt(i);
}
}
Your results list will be:
b
c
d
Leaving the above for reference, but to #LarsTech comment below, list.RemoveAt breaks the loop so it will only remove 1 item. If you are wanting to remove multiple items, Alex's other answer with the Linq would be the cleanest way to remove it.
If you don't want to create a second list to house the items to be deleted, you can also do the below:
for (int i = 0; i < list.Count(); i++)
{
if (list[i].Contains("a"))
{
list = list.Where(x => !x.Contains("a")).ToList();
}
}

When you loop over a list with foreach and try to remove an item, you will get a runtime InvalidOperationException:
Collection was modified, enumeration operation may not execute
So you can use a for loop, which can handle modifications to the list. However, when you delete an item, all higher indexes will shift down. This will mean you skip an item.
The solution is to iterate in reverse order:
var list = new List<string>();
list.Add("a");
list.Add("b");
list.Add("b");
list.Add("c");
list.Add("d");
for (int i = list.Count()-1; i>=0; i--)
{
if (list[i].Contains("b"))
{
list.RemoveAt(i);
}
}
// result: a, c, d
you have to start at "count - 1", because that is the highest actual index
the last index to use is 0 (the start of the list)
and decrease the index after every iteration

Related

C# Trying to return indexes on duplicated items inside a list, but the loop keeps returning the index of only the first duplicate

Whenever I run this, I want to have the index's of the list items to be displayed. However when i have the loop search for one of the items on the list, it will give me multiple indexes, but it's only the index of the item that comes first in the list. So if there were 2 instances of that list item, it would give me the indices of 1 and 1(Example).
Console.WriteLine("\n\nPress enter to display team list with duplications");
Console.ReadLine();
List<string> teamList = new List<string>();
teamList.Add("cubs");
teamList.Add("red sox");
teamList.Add("yankees");
teamList.Add("cubs");
teamList.Add("yankees");
teamList.Add("yankees");
foreach (string teams in teamList)
{
Console.WriteLine(teams);
}
Console.WriteLine("Select an item in the list: ");
string teamSelected = Console.ReadLine();
List<int> indexList = new List<int>();
if (teamList.Contains(teamSelected))
{
foreach (string teams in teamList)
{
if (teams == teamSelected)
{
Console.WriteLine(teamList.IndexOf(teams));
}
}
}
else { Console.WriteLine("That is not an option!"); }
You're asking it to give you the index of teams using .IndexOf(). Even if there are multiple indices with the same value, e.g. teamList[0] has the same value as teamList[3], .IndexOf() will always return the first index found.
To remedy this, you should use a for loop instead of a foreach loop like so:
for(int index = 0; index < teamList.Count; index++)
if(teamList[i] == teamSelected)
Console.WriteLine(i);
List.Count gets the amount of items stored in List.

c#: Remove item from List and continue Foreach loop [duplicate]

I am looking for a better pattern for working with a list of elements which each need processed and then depending on the outcome are removed from the list.
You can't use .Remove(element) inside a foreach (var element in X) (because it results in Collection was modified; enumeration operation may not execute. exception)... you also can't use for (int i = 0; i < elements.Count(); i++) and .RemoveAt(i) because it disrupts your current position in the collection relative to i.
Is there an elegant way to do this?
Iterate your list in reverse with a for loop:
for (int i = safePendingList.Count - 1; i >= 0; i--)
{
// some code
// safePendingList.RemoveAt(i);
}
Example:
var list = new List<int>(Enumerable.Range(1, 10));
for (int i = list.Count - 1; i >= 0; i--)
{
if (list[i] > 5)
list.RemoveAt(i);
}
list.ForEach(i => Console.WriteLine(i));
Alternately, you can use the RemoveAll method with a predicate to test against:
safePendingList.RemoveAll(item => item.Value == someValue);
Here's a simplified example to demonstrate:
var list = new List<int>(Enumerable.Range(1, 10));
Console.WriteLine("Before:");
list.ForEach(i => Console.WriteLine(i));
list.RemoveAll(i => i > 5);
Console.WriteLine("After:");
list.ForEach(i => Console.WriteLine(i));
foreach (var item in list.ToList()) {
list.Remove(item);
}
If you add ".ToList()" to your list (or the results of a LINQ query), you can remove "item" directly from "list" without the dreaded "Collection was modified; enumeration operation may not execute." error. The compiler makes a copy of "list", so that you can safely do the remove on the array.
While this pattern is not super efficient, it has a natural feel and is flexible enough for almost any situation. Such as when you want to save each "item" to a DB and remove it from the list only when the DB save succeeds.
A simple and straightforward solution:
Use a standard for-loop running backwards on your collection and RemoveAt(i) to remove elements.
Reverse iteration should be the first thing to come to mind when you want to remove elements from a Collection while iterating over it.
Luckily, there is a more elegant solution than writing a for loop which involves needless typing and can be error prone.
ICollection<int> test = new List<int>(new int[] {1, 2, 3, 4, 5, 6, 7, 8, 9, 10});
foreach (int myInt in test.Reverse<int>())
{
if (myInt % 2 == 0)
{
test.Remove(myInt);
}
}
Using the ToArray() on a generic list allows you to do a Remove(item) on your generic List:
List<String> strings = new List<string>() { "a", "b", "c", "d" };
foreach (string s in strings.ToArray())
{
if (s == "b")
strings.Remove(s);
}
Select the elements you do want rather than trying to remove the elements you don't want. This is so much easier (and generally more efficient too) than removing elements.
var newSequence = (from el in list
where el.Something || el.AnotherThing < 0
select el);
I wanted to post this as a comment in response to the comment left by Michael Dillon below, but it's too long and probably useful to have in my answer anyway:
Personally, I'd never remove items one-by-one, if you do need removal, then call RemoveAll which takes a predicate and only rearranges the internal array once, whereas Remove does an Array.Copy operation for every element you remove. RemoveAll is vastly more efficient.
And when you're backwards iterating over a list, you already have the index of the element you want to remove, so it would be far more efficient to call RemoveAt, because Remove first does a traversal of the list to find the index of the element you're trying to remove, but you already know that index.
So all in all, I don't see any reason to ever call Remove in a for-loop. And ideally, if it is at all possible, use the above code to stream elements from the list as needed so no second data structure has to be created at all.
Using .ToList() will make a copy of your list, as explained in this question:
ToList()-- Does it Create a New List?
By using ToList(), you can remove from your original list, because you're actually iterating over a copy.
foreach (var item in listTracked.ToList()) {
if (DetermineIfRequiresRemoval(item)) {
listTracked.Remove(item)
}
}
If the function that determines which items to delete has no side effects and doesn't mutate the item (it's a pure function), a simple and efficient (linear time) solution is:
list.RemoveAll(condition);
If there are side effects, I'd use something like:
var toRemove = new HashSet<T>();
foreach(var item in items)
{
...
if(condition)
toRemove.Add(item);
}
items.RemoveAll(toRemove.Contains);
This is still linear time, assuming the hash is good. But it has an increased memory use due to the hashset.
Finally if your list is only an IList<T> instead of a List<T> I suggest my answer to How can I do this special foreach iterator?. This will have linear runtime given typical implementations of IList<T>, compared with quadratic runtime of many other answers.
As any remove is taken on a condition you can use
list.RemoveAll(item => item.Value == someValue);
List<T> TheList = new List<T>();
TheList.FindAll(element => element.Satisfies(Condition)).ForEach(element => TheList.Remove(element));
You can't use foreach, but you could iterate forwards and manage your loop index variable when you remove an item, like so:
for (int i = 0; i < elements.Count; i++)
{
if (<condition>)
{
// Decrement the loop counter to iterate this index again, since later elements will get moved down during the remove operation.
elements.RemoveAt(i--);
}
}
Note that in general all of these techniques rely on the behaviour of the collection being iterated. The technique shown here will work with the standard List(T). (It is quite possible to write your own collection class and iterator that does allow item removal during a foreach loop.)
For loops are a bad construct for this.
Using while
var numbers = new List<int>(Enumerable.Range(1, 3));
while (numbers.Count > 0)
{
numbers.RemoveAt(0);
}
But, if you absolutely must use for
var numbers = new List<int>(Enumerable.Range(1, 3));
for (; numbers.Count > 0;)
{
numbers.RemoveAt(0);
}
Or, this:
public static class Extensions
{
public static IList<T> Remove<T>(
this IList<T> numbers,
Func<T, bool> predicate)
{
numbers.ForEachBackwards(predicate, (n, index) => numbers.RemoveAt(index));
return numbers;
}
public static void ForEachBackwards<T>(
this IList<T> numbers,
Func<T, bool> predicate,
Action<T, int> action)
{
for (var i = numbers.Count - 1; i >= 0; i--)
{
if (predicate(numbers[i]))
{
action(numbers[i], i);
}
}
}
}
Usage:
var numbers = new List<int>(Enumerable.Range(1, 10)).Remove((n) => n > 5);
However, LINQ already has RemoveAll() to do this
var numbers = new List<int>(Enumerable.Range(1, 10));
numbers.RemoveAll((n) => n > 5);
Lastly, you are probably better off using LINQ's Where() to filter and create a new list instead of mutating the existing list. Immutability is usually good.
var numbers = new List<int>(Enumerable.Range(1, 10))
.Where((n) => n <= 5)
.ToList();
Using Remove or RemoveAt on a list while iterating over that list has intentionally been made difficult, because it is almost always the wrong thing to do. You might be able to get it working with some clever trick, but it would be extremely slow. Every time you call Remove it has to scan through the entire list to find the element you want to remove. Every time you call RemoveAt it has to move subsequent elements 1 position to the left. As such, any solution using Remove or RemoveAt, would require quadratic time, O(n²).
Use RemoveAll if you can. Otherwise, the following pattern will filter the list in-place in linear time, O(n).
// Create a list to be filtered
IList<int> elements = new List<int>(new int[] {1, 2, 3, 4, 5, 6, 7, 8, 9, 10});
// Filter the list
int kept = 0;
for (int i = 0; i < elements.Count; i++) {
// Test whether this is an element that we want to keep.
if (elements[i] % 3 > 0) {
// Add it to the list of kept elements.
elements[kept] = elements[i];
kept++;
}
}
// Unfortunately IList has no Resize method. So instead we
// remove the last element of the list until: elements.Count == kept.
while (kept < elements.Count) elements.RemoveAt(elements.Count-1);
I would reassign the list from a LINQ query that filtered out the elements you didn't want to keep.
list = list.Where(item => ...).ToList();
Unless the list is very large there should be no significant performance problems in doing this.
The best way to remove items from a list while iterating over it is to use RemoveAll(). But the main concern written by people is that they have to do some complex things inside the loop and/or have complex compare cases.
The solution is to still use RemoveAll() but use this notation:
var list = new List<int>(Enumerable.Range(1, 10));
list.RemoveAll(item =>
{
// Do some complex operations here
// Or even some operations on the items
SomeFunction(item);
// In the end return true if the item is to be removed. False otherwise
return item > 5;
});
By assuming that predicate is a Boolean property of an element, that if it is true, then the element should be removed:
int i = 0;
while (i < list.Count())
{
if (list[i].predicate == true)
{
list.RemoveAt(i);
continue;
}
i++;
}
In C# one easy way is to mark the ones you wish to delete then create a new list to iterate over...
foreach(var item in list.ToList()){if(item.Delete) list.Remove(item);}
or even simpler use linq....
list.RemoveAll(p=>p.Delete);
but it is worth considering if other tasks or threads will have access to the same list at the same time you are busy removing, and maybe use a ConcurrentList instead.
I wish the "pattern" was something like this:
foreach( thing in thingpile )
{
if( /* condition#1 */ )
{
foreach.markfordeleting( thing );
}
elseif( /* condition#2 */ )
{
foreach.markforkeeping( thing );
}
}
foreachcompleted
{
// then the programmer's choices would be:
// delete everything that was marked for deleting
foreach.deletenow(thingpile);
// ...or... keep only things that were marked for keeping
foreach.keepnow(thingpile);
// ...or even... make a new list of the unmarked items
others = foreach.unmarked(thingpile);
}
This would align the code with the process that goes on in the programmer's brain.
foreach(var item in list.ToList())
{
if(item.Delete) list.Remove(item);
}
Simply create an entirely new list from the first one. I say "Easy" rather than "Right" as creating an entirely new list probably comes at a performance premium over the previous method (I haven't bothered with any benchmarking.) I generally prefer this pattern, it can also be useful in overcoming Linq-To-Entities limitations.
for(i = list.Count()-1;i>=0;i--)
{
item=list[i];
if (item.Delete) list.Remove(item);
}
This way cycles through the list backwards with a plain old For loop. Doing this forwards could be problematic if the size of the collection changes, but backwards should always be safe.
Just wanted to add my 2 cents to this in case this helps anyone, I had a similar problem but needed to remove multiple elements from an array list while it was being iterated over. the highest upvoted answer did it for me for the most part until I ran into errors and realized that the index was greater than the size of the array list in some instances because multiple elements were being removed but the index of the loop didn't keep track of that. I fixed this with a simple check:
ArrayList place_holder = new ArrayList();
place_holder.Add("1");
place_holder.Add("2");
place_holder.Add("3");
place_holder.Add("4");
for(int i = place_holder.Count-1; i>= 0; i--){
if(i>= place_holder.Count){
i = place_holder.Count-1;
}
// some method that removes multiple elements here
}
There is an option that hasn't been mentioned here.
If you don't mind adding a bit of code somewhere in your project, you can add and extension to List to return an instance of a class that does iterate through the list in reverse.
You would use it like this :
foreach (var elem in list.AsReverse())
{
//Do stuff with elem
//list.Remove(elem); //Delete it if you want
}
And here is what the extension looks like:
public static class ReverseListExtension
{
public static ReverseList<T> AsReverse<T>(this List<T> list) => new ReverseList<T>(list);
public class ReverseList<T> : IEnumerable
{
List<T> list;
public ReverseList(List<T> list){ this.list = list; }
public IEnumerator GetEnumerator()
{
for (int i = list.Count - 1; i >= 0; i--)
yield return list[i];
yield break;
}
}
}
This is basically list.Reverse() without the allocation.
Like some have mentioned you still get the drawback of deleting elements one by one, and if your list is massively long some of the options here are better. But I think there is a world where someone would want the simplicity of list.Reverse(), without the memory overhead.
Copy the list you are iterating. Then remove from the copy and interate the original. Going backwards is confusing and doesn't work well when looping in parallel.
var ids = new List<int> { 1, 2, 3, 4 };
var iterableIds = ids.ToList();
Parallel.ForEach(iterableIds, id =>
{
ids.Remove(id);
});
I would do like this
using System.IO;
using System;
using System.Collections.Generic;
class Author
{
public string Firstname;
public string Lastname;
public int no;
}
class Program
{
private static bool isEven(int i)
{
return ((i % 2) == 0);
}
static void Main()
{
var authorsList = new List<Author>()
{
new Author{ Firstname = "Bob", Lastname = "Smith", no = 2 },
new Author{ Firstname = "Fred", Lastname = "Jones", no = 3 },
new Author{ Firstname = "Brian", Lastname = "Brains", no = 4 },
new Author{ Firstname = "Billy", Lastname = "TheKid", no = 1 }
};
authorsList.RemoveAll(item => isEven(item.no));
foreach(var auth in authorsList)
{
Console.WriteLine(auth.Firstname + " " + auth.Lastname);
}
}
}
OUTPUT
Fred Jones
Billy TheKid
I found myself in a similar situation where I had to remove every nth element in a given List<T>.
for (int i = 0, j = 0, n = 3; i < list.Count; i++)
{
if ((j + 1) % n == 0) //Check current iteration is at the nth interval
{
list.RemoveAt(i);
j++; //This extra addition is necessary. Without it j will wrap
//down to zero, which will throw off our index.
}
j++; //This will always advance the j counter
}
The cost of removing an item from the list is proportional to the number of items following the one to be removed. In the case where the first half of the items qualify for removal, any approach which is based upon removing items individually will end up having to perform about N*N/4 item-copy operations, which can get very expensive if the list is large.
A faster approach is to scan through the list to find the first item to be removed (if any), and then from that point forward copy each item which should be retained to the spot where it belongs. Once this is done, if R items should be retained, the first R items in the list will be those R items, and all of the items requiring deletion will be at the end. If those items are deleted in reverse order, the system won't end up having to copy any of them, so if the list had N items of which R items, including all of the first F, were retained,
it will be necessary to copy R-F items, and shrink the list by one item N-R times. All linear time.
My approach is that I first create a list of indices, which should get deleted. Afterwards I loop over the indices and remove the items from the initial list. This looks like this:
var messageList = ...;
// Restrict your list to certain criteria
var customMessageList = messageList.FindAll(m => m.UserId == someId);
if (customMessageList != null && customMessageList.Count > 0)
{
// Create list with positions in origin list
List<int> positionList = new List<int>();
foreach (var message in customMessageList)
{
var position = messageList.FindIndex(m => m.MessageId == message.MessageId);
if (position != -1)
positionList.Add(position);
}
// To be able to remove the items in the origin list, we do it backwards
// so that the order of indices stays the same
positionList = positionList.OrderByDescending(p => p).ToList();
foreach (var position in positionList)
{
messageList.RemoveAt(position);
}
}
Trace the elements to be removed with a property, and remove them all after process.
using System.Linq;
List<MyProperty> _Group = new List<MyProperty>();
// ... add elements
bool cond = false;
foreach (MyProperty currObj in _Group)
{
// here it is supposed that you decide the "remove conditions"...
cond = true; // set true or false...
if (cond)
{
// SET - element can be deleted
currObj.REMOVE_ME = true;
}
}
// RESET
_Group.RemoveAll(r => r.REMOVE_ME);
myList.RemoveAt(i--);
simples;

C# for loop skipping last item

I have the below for loop
int listCount = _itemCollection.Count;
//_itemCollection is of type SPListItemCollection
for (int i=0;i<listCount;i++)
{
var item = _itemCollection[i]; // just to prevent changes in all places inside the for loop
if(item['expirydate']>today){
item.delete();
listCount--; //as I am removing 1 item, I am decrementing count
}
}
In this for loop, I am iterating through the items in itemcollection and deleting some of them. i.e item will be removed from itemcollection array and so itemcollection.count will be reduced by 1
This is not deleting the 3rd item every time, when I have 3 items to delete
I am not sure what condition should be used for getting it right
You should go in the reverse order as below and use for instead of foreach as below.
int listCount = _itemCollection.Count;
for (int i = listCount - 1; i >= 0; i--)
{
var item = _itemCollection[i]; // just to prevent changes in all places inside the for loop
if(item['expirydate'] > today){
item.delete();
}
}
You can do something like this:
_itemCollection.RemoveAll(item => item['expirydate'] > today);
This removes all the items that matches the given condition.
To remove item from SPListItemCollection check this documentation
Try this:
int listCount = _itemCollection.Count;
for (int i = 0; i < listCount; i++)
{
var item = _itemCollection[i];
if(item [expirydate] > today)
{
_itemCollection.Remove(item);
listCount--;
}
}
This may fulfill your want. Here you can directly use _itemCollection[i] instead of item.
I hope this may help you. Enjoy coding.

Change List inside a for loop

I'm trying to modify a list inside a for value
for (int i = 0; i < theList.Count; i++) {
if(someCircunstances)
theList.remove(component);
else
theList.add(component);
}
I get an ArgumentOutOfRangeException with this method.
Is there any method to accomplish this?
It can be solved by iterating backwards and using indexes instead of items:
for (int i = list.Count - 1; i > 0; i--)
{
if(condition)
list.RemoveAt(i);
else
list.Add(component);
}
Some explanation: when you iterating over collection you shouldn't change items in the scope. Iterators will detect that and throw (and in case of foreach you must use copy of list). But in case of using indexes (RemoveAt() method) and when iterating backward you are safe as for next iteration the scope doesn't include deleted items. Add() is adding to the end, therefore new item is never in scope.
I'll add few more solutions, which one is better decide yourself:
Classical foreach with copy first:
foreach(var item in list.ToArray()) // imho `ToArray` is better than `ToList`
if(condition)
list.Remove(item);
else
list.Add(component);
New list as result:
var result = new List<...>();
foreach(var item in list)
result.Add(condition ? component : item); // not sure here, but should give you idea
list = result;
This is also a bad practice to mutate the list while iterating over it.
This is an alternative:
theList.RemoveAll(someCircunstances);
you are getting an out of range exception because indexes start on 0.
as stated above, one solution is to remove 1 from theList.count, and another solution is to initiate i at 1 instead of 0.
think of this: if your list has 1 element in it, the index of that element is 0, if you have 100 elements, the index of your hundreth element is 99.
you are thinking of the list like: [1][2][3], while it's actually [0][1][2]
The problem here is that you are deleting values out of the list and then you iterate throught it again with an index which is already removed -> ArgumentOutOfRangeException
So to solve this i suggest you to split it up to two for loops:
for (int i = theList.Count - 1; i >= 0; i--) {
if(someCircunstances)
theList.remove(component);
}
for (int i = 0; i < theList.Count; i++) {
if(someCircunstances)
theList.add(component);
}
I am agree with Tamas, that don't mutate the list while iterating , there is another way to achieve your point
List<someType> ToRemove=new List<someType>() ; //some type is same type as theList is
List<someType> ToAdd=new List<someType>();
for (int i = 0; i < theList.Count; i++) {
if(someCircunstances)
ToRemove.add(component);
else
ToAdd.add(component);
}
theList=((theList.Except(ToRemove)).Concat(ToAdd)).ToList();
Based on the comments, you need to be able to apply the same logic for newly created items.
You need to do something like this:
public void DoIt(List<MyObject> theList)
{
List<MyObject> items_to_remove = new List<MyObject>();
List<MyObject> items_to_add = new List<MyObject>();
for (int i = 0; i < theList.Count; i++)
{
if (someCircunstances)
items_to_remove.Add(....); //Remove some existing item
else
items_to_add.Add(....); //Add a new item
}
if(items_to_remove.Count > 0)
items_to_remove.ForEach(x => theList.Remove(x));
if (items_to_add.Count > 0)
{
DoIt(items_to_add); //Recursively process new objects
theList.AddRange(items_to_add);
}
}
The idea is that you insert the items to add and the items to remove in their own lists.
Then after the iteration, you remove the items that need to be removed.
After that you need to add the items to add. However, before doing that you need to run the same logic on them, and that is the explanation for the recursive call.
Please note that I am using MyObject because I don't know the type of your list. Use whatever type that you are working with.
If you can use the current index of the loop to remove the item from the lst, you can do this easily like so:
using System;
using System.Linq;
namespace ConsoleApplication1
{
class Program
{
static void Main()
{
var numbers = Enumerable.Range(1, 20).ToList();
var rng = new Random();
for (int i = 0; i < numbers.Count; ++i)
{
if (rng.NextDouble() >= 0.5) // If "someCircumstances"
{
numbers.Add(numbers[i]*2);
}
else
{
// Assume here you have some way to determine the
// index of the item to remove.
// For demo purposes, I'll just calculate a random index.
int index = rng.Next(0, numbers.Count);
if (index >= i)
--i;
numbers.RemoveAt(index);
}
}
Console.WriteLine(string.Join("\n", numbers));
}
}
}
This will also loop over all the numbers added to the end of the list. The value of numbers.Count is recomputed at each iteration, so when it changes, the loop will be extended appropriately.
(Offtopic) BONUS QUESTION: In the above code, what will be the average size of the list when the loop exits? And what would be the maximum size?

How to modify or delete items from an enumerable collection while iterating through it in C#

I have to delete some rows from a data table. I've heard that it is not ok to change a collection while iterating through it. So instead of a for loop in which I check if a row meets the demands for deletion and then mark it as deleted, I should first iterate through the data table and add all of the rows in a list, then iterate through the list and mark the rows for deletions. What are the reasons for this, and what alternatives do I have (instead of using the rows list I mean)?.
Iterating Backwards through the List sounds like a better approach, because if you remove an element and other elements "fall into the gap", that does not matter because you have already looked at those. Also, you do not have to worry about your counter variable becoming larger than the .Count.
List<int> test = new List<int>();
test.Add(1);
test.Add(2);
test.Add(3);
test.Add(4);
test.Add(5);
test.Add(6);
test.Add(7);
test.Add(8);
for (int i = test.Count-1; i > -1; i--)
{
if(someCondition){
test.RemoveAt(i);
}
}
Taking #bruno code, I'd do it backwards.
Because when you move backwards, the missing array indices do not interfere with the order of your loop.
var l = new List<int>(new int[] { 0, 1, 2, 3, 4, 5, 6 });
for (int i = l.Count - 1; i >= 0; i--)
if (l[i] % 2 == 0)
l.RemoveAt(i);
foreach (var i in l)
{
Console.WriteLine(i);
}
But seriuosly, these days, I'd use LINQ:
var l = new List<int>(new int[] { 0, 1, 2, 3, 4, 5, 6 });
l.RemoveAll(n => n % 2 == 0);
You can remove elements from a collection if you use a simple for loop.
Take a look at this example:
var l = new List<int>();
l.Add(0);
l.Add(1);
l.Add(2);
l.Add(3);
l.Add(4);
l.Add(5);
l.Add(6);
for (int i = 0; i < l.Count; i++)
{
if (l[i] % 2 == 0)
{
l.RemoveAt(i);
i--;
}
}
foreach (var i in l)
{
Console.WriteLine(i);
}
Since you're working with a DataTable and need to be able to persist any changes back to the server with a table adapter (see comments), here is an example of how you should delete rows:
DataTable dt;
// remove all rows where the last name starts with "B"
foreach (DataRow row in dt.Rows)
{
if (row["LASTNAME"].ToString().StartsWith("B"))
{
// mark the row for deletion:
row.Delete();
}
}
Calling delete on the rows will change their RowState property to Deleted, but leave the deleted rows in the table. If you still need to work with this table before persisting changes back to the server (like if you want to display the table's contents minus the deleted rows), you need to check the RowState of each row as you're iterating through it like this:
foreach (DataRow row in dt.Rows)
{
if (row.RowState != DataRowState.Deleted)
{
// this row has not been deleted - go ahead and show it
}
}
Removing rows from the collection (as in bruno's answer) will break the table adapter, and should generally not be done with a DataTable.
A while loop would handle this:
int i = 0;
while(i < list.Count)
{
if(<codition for removing element met>)
{
list.RemoveAt(i);
}
else
{
i++;
}
}
chakrit's solution can also be used if you are targetting .NET 2.0 (no LINQ/lambda expressions) by using a delegate rather than a lambda expression:
public bool IsMatch(int item) {
return (item % 3 == 1); // put whatever condition you want here
}
public void RemoveMatching() {
List<int> x = new List<int>();
x.RemoveAll(new Predicate<int>(IsMatch));
}
Deleting or adding to the list whilst iterating through it can break it, like you said.
I often used a two list approach to solve the problem:
ArrayList matches = new ArrayList(); //second list
for MyObject obj in my_list
{
if (obj.property == value_i_care_about)
matches.addLast(obj);
}
//now modify
for MyObject m in matches
{
my_list.remove(m); //use second list to delete from first list
}
//finished.
When I need to remove an item from a collection that I am enumerating I usually enumerate it in reverse.

Categories