Possible to modify a List while iterating through it? - c#

I have the following:
foreach (var depthCard in depthCards)
{
var card = InternalGetCard(db, depthCard.CardId);
var set = InternalGetSet(db, (int)card.ParentSetId);
var depthArray = InternalGetDepthArrayForCard(db, set.SetId);
foreach (var cardToUpdate in set.Cards)
{
// do stuff
SaveChanges(db);
// since I already took care of it here, remove from depthCards
depthCards.Remove(depthCardToUpdate);
}
}
This isn't working though because I'm modifying the collection in the middle of a loop. Is there some type of collection that does allow this type of access?
I don't want to ToList() the depthCards because I already have them and I want to modify that list as I'm iterating. Is this possible?

It's possible, the trick is to iterate backwards:
for (int i = depthCards.Count - 1; i >= 0; i--) {
if (depthCards[i] == something) { // condition to remove element, if applicable
depthCards.RemoveAt(i);
}
}

You can iterate backwards with a for-loop
for (int i = depthCards.Count - 1; i >= 0; i--)
{
depthCards.RemoveAt(i);
}
or if you just want to remove items on a condition, use List.RemoveAll:
depthCardToUpdate.RemoveAll(dc => conditionHere);

You can create a custom enumerator that handles this for you. I did this once and it was a bit tricky but worked after some finesse.
See: http://www.codeproject.com/Articles/28963/Custom-Enumerators

Related

How to remove a scriptable object from a list of scriptable objects? [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;

Remove element from collection using IEnumerator in C#

I need to remove an element from a list<> in C#. From the previous answers provided, it seems that one has to loop backwards through the collection to achieve this. But, I have an IEnumerator to iterate through elements of the list.
The code is as follows:
IEnumerator<Solution> iterator = solutionsList_.GetEnumerator();
while (iterator.MoveNext())
{
Solution element = iterator.Current;
int flag = dominance_.Compare(solution, element);
if (flag == -1) { // The Individual to insert dominates other
// individuals in the archive
iterator.Remove();} // Delete it from the archive
It would be very helpful if I could get some way of removing the element from the list<> along with using the enumerator.
Since you have a List<T>, then there's no reason to explicitly grab the enumerator. You can just use a regular loop, and go backwards - and you'll be able to remove elements without any issue, here is a code sample:
var solutionsList_ = new List<int>();
for (var i = solutionsList_.Count - 1; i >= 0; i--)
{
var element = solutionsList_[i];
//if (Some logic)
{
solutionsList_.RemoveAt(i);
}
}
IEnumerable's can only been enumerated, you cannot add/remove an item from it.
You can use an ICollection to add/remove items, you can try casting your IEnumerable to an ICollection as List implements ICollection.
http://msdn.microsoft.com/en-us/library/system.collections.ienumerable.aspx
I think You are complicating the scenario. You can Directly apply LINQ extension methods over List. So You can simply use the following code to remove the Items from the List:
List<Solution> solutionsList_ = new List<Solution>() { };
// Populate the list here
var itemsToRemove = solutionsList_.Where(x => dominance_.Compare(solution, x) == -1);
foreach (var item in itemsToRemove)
{
solutionsList_.Remove(item);
}

Intelligent way of removing items from a List<T> while enumerating in C#

I have the classic case of trying to remove an item from a collection while enumerating it in a loop:
List<int> myIntCollection = new List<int>();
myIntCollection.Add(42);
myIntCollection.Add(12);
myIntCollection.Add(96);
myIntCollection.Add(25);
foreach (int i in myIntCollection)
{
if (i == 42)
myIntCollection.Remove(96); // The error is here.
if (i == 25)
myIntCollection.Remove(42); // The error is here.
}
At the beginning of the iteration after a change takes place, an InvalidOperationException is thrown, because enumerators don’t like when the underlying collection changes.
I need to make changes to the collection while iterating. There are many patterns that can be used to avoid this, but none of them seems to have a good solution:
Do not delete inside this loop, instead keep a separate “Delete List”, that you process after the main loop.
This is normally a good solution, but in my case, I need the item to be gone instantly as “waiting” till after
the main loop to really delete the item changes the logic flow of my code.
Instead of deleting the item, simply set a flag on the item and mark it as inactive. Then add the functionality of pattern 1 to clean up the list.
This would work for all of my needs, but it means that a lot of code will have to change in order to check the inactive flag every time an item is accessed. This is far too much administration for my liking.
Somehow incorporate the ideas of pattern 2 in a class that derives from List<T>. This Superlist will handle the inactive flag, the deletion of objects after the fact and also will not expose items marked as inactive to enumeration consumers. Basically, it just encapsulates all the ideas of pattern 2 (and subsequently pattern 1).
Does a class like this exist? Does anyone have code for this? Or is there a better way?
I’ve been told that accessing myIntCollection.ToArray() instead of myIntCollection will solve the problem and allow me to delete inside the loop.
This seems like a bad design pattern to me, or maybe it’s fine?
Details:
The list will contain many items and I will be removing only some of them.
Inside the loop, I will be doing all sorts of processes, adding, removing etc., so the solution needs to be fairly generic.
The item that I need to delete may not be the current item in the loop. For example, I may be on item 10 of a 30 item loop and need to remove item 6 or item 26. Walking backwards through the array will no longer work because of this. ;o(
The best solution is usually to use the RemoveAll() method:
myList.RemoveAll(x => x.SomeProp == "SomeValue");
Or, if you need certain elements removed:
MyListType[] elems = new[] { elem1, elem2 };
myList.RemoveAll(x => elems.Contains(x));
This assume that your loop is solely intended for removal purposes, of course. If you do need to additional processing, then the best method is usually to use a for or while loop, since then you're not using an enumerator:
for (int i = myList.Count - 1; i >= 0; i--)
{
// Do processing here, then...
if (shouldRemoveCondition)
{
myList.RemoveAt(i);
}
}
Going backwards ensures that you don't skip any elements.
Response to Edit:
If you're going to have seemingly arbitrary elements removed, the easiest method might be to just keep track of the elements you want to remove, and then remove them all at once after. Something like this:
List<int> toRemove = new List<int>();
foreach (var elem in myList)
{
// Do some stuff
// Check for removal
if (needToRemoveAnElement)
{
toRemove.Add(elem);
}
}
// Remove everything here
myList.RemoveAll(x => toRemove.Contains(x));
If you must both enumerate a List<T> and remove from it then I suggest simply using a while loop instead of a foreach
var index = 0;
while (index < myList.Count) {
if (someCondition(myList[index])) {
myList.RemoveAt(index);
} else {
index++;
}
}
I know this post is old, but I thought I'd share what worked for me.
Create a copy of the list for enumerating, and then in the for each loop, you can process on the copied values, and remove/add/whatever with the source list.
private void ProcessAndRemove(IList<Item> list)
{
foreach (var item in list.ToList())
{
if (item.DeterminingFactor > 10)
{
list.Remove(item);
}
}
}
When you need to iterate through a list and might modify it during the loop then you are better off using a for loop:
for (int i = 0; i < myIntCollection.Count; i++)
{
if (myIntCollection[i] == 42)
{
myIntCollection.Remove(i);
i--;
}
}
Of course you must be careful, for example I decrement i whenever an item is removed as otherwise we will skip entries (an alternative is to go backwards though the list).
If you have Linq then you should just use RemoveAll as dlev has suggested.
As you enumerate the list, add the one you want to KEEP to a new list. Afterward, assign the new list to the myIntCollection
List<int> myIntCollection=new List<int>();
myIntCollection.Add(42);
List<int> newCollection=new List<int>(myIntCollection.Count);
foreach(int i in myIntCollection)
{
if (i want to delete this)
///
else
newCollection.Add(i);
}
myIntCollection = newCollection;
Let's add you code:
List<int> myIntCollection=new List<int>();
myIntCollection.Add(42);
myIntCollection.Add(12);
myIntCollection.Add(96);
myIntCollection.Add(25);
If you want to change the list while you're in a foreach, you must type .ToList()
foreach(int i in myIntCollection.ToList())
{
if (i == 42)
myIntCollection.Remove(96);
if (i == 25)
myIntCollection.Remove(42);
}
For those it may help, I wrote this Extension method to remove items matching the predicate and return the list of removed items.
public static IList<T> RemoveAllKeepRemoved<T>(this IList<T> source, Predicate<T> predicate)
{
IList<T> removed = new List<T>();
for (int i = source.Count - 1; i >= 0; i--)
{
T item = source[i];
if (predicate(item))
{
removed.Add(item);
source.RemoveAt(i);
}
}
return removed;
}
How about
int[] tmp = new int[myIntCollection.Count ()];
myIntCollection.CopyTo(tmp);
foreach(int i in tmp)
{
myIntCollection.Remove(42); //The error is no longer here.
}
If you're interested in high performance, you can use two lists. The following minimises garbage collection, maximises memory locality and never actually removes an item from a list, which is very inefficient if it's not the last item.
private void RemoveItems()
{
_newList.Clear();
foreach (var item in _list)
{
item.Process();
if (!item.NeedsRemoving())
_newList.Add(item);
}
var swap = _list;
_list = _newList;
_newList = swap;
}
Just figured I'll share my solution to a similar problem where i needed to remove items from a list while processing them.
So basically "foreach" that will remove the item from the list after it has been iterated.
My test:
var list = new List<TempLoopDto>();
list.Add(new TempLoopDto("Test1"));
list.Add(new TempLoopDto("Test2"));
list.Add(new TempLoopDto("Test3"));
list.Add(new TempLoopDto("Test4"));
list.PopForEach((item) =>
{
Console.WriteLine($"Process {item.Name}");
});
Assert.That(list.Count, Is.EqualTo(0));
I solved this with a extension method "PopForEach" that will perform a action and then remove the item from the list.
public static class ListExtensions
{
public static void PopForEach<T>(this List<T> list, Action<T> action)
{
var index = 0;
while (index < list.Count) {
action(list[index]);
list.RemoveAt(index);
}
}
}
Hope this can be helpful to any one.
Currently you are using a list. If you could use a dictionary instead, it would be much easier. I'm making some assumptions that you are really using a class instead of just a list of ints. This would work if you had some form of unique key. In the dictionary, object can be any class you have and int would be any unique key.
Dictionary<int, object> myIntCollection = new Dictionary<int, object>();
myIntCollection.Add(42, "");
myIntCollection.Add(12, "");
myIntCollection.Add(96, "");
myIntCollection.Add(25, "");
foreach (int i in myIntCollection.Keys)
{
//Check to make sure the key wasn't already removed
if (myIntCollection.ContainsKey(i))
{
if (i == 42) //You can test against the key
myIntCollection.Remove(96);
if (myIntCollection[i] == 25) //or you can test against the value
myIntCollection.Remove(42);
}
}
Or you could use
Dictionary<myUniqueClass, bool> myCollection; //Bool is just an empty place holder
The nice thing is you can do anything you want to the underlying dictionary and the key enumerator doesn't care, but it also doesn't update with added or removed entries.

What is the best way to modify a list in a 'foreach' loop?

A new feature in C# / .NET 4.0 is that you can change your enumerable in a foreach without getting the exception. See Paul Jackson's blog entry An Interesting Side-Effect of Concurrency: Removing Items from a Collection While Enumerating for information on this change.
What is the best way to do the following?
foreach(var item in Enumerable)
{
foreach(var item2 in item.Enumerable)
{
item.Add(new item2)
}
}
Usually I use an IList as a cache/buffer until the end of the foreach, but is there better way?
The collection used in foreach is immutable. This is very much by design.
As it says on MSDN:
The foreach statement is used to
iterate through the collection to get
the information that you want, but can
not be used to add or remove items
from the source collection to avoid
unpredictable side effects. If you
need to add or remove items from the
source collection, use a for loop.
The post in the link provided by Poko indicates that this is allowed in the new concurrent collections.
Make a copy of the enumeration, using an IEnumerable extension method in this case, and enumerate over it. This would add a copy of every element in every inner enumerable to that enumeration.
foreach(var item in Enumerable)
{
foreach(var item2 in item.Enumerable.ToList())
{
item.Add(item2)
}
}
To illustrate Nippysaurus's answer: If you are going to add the new items to the list and want to process the newly added items too during the same enumeration then you can just use for loop instead of foreach loop, problem solved :)
var list = new List<YourData>();
... populate the list ...
//foreach (var entryToProcess in list)
for (int i = 0; i < list.Count; i++)
{
var entryToProcess = list[i];
var resultOfProcessing = DoStuffToEntry(entryToProcess);
if (... condition ...)
list.Add(new YourData(...));
}
For runnable example:
void Main()
{
var list = new List<int>();
for (int i = 0; i < 10; i++)
list.Add(i);
//foreach (var entry in list)
for (int i = 0; i < list.Count; i++)
{
var entry = list[i];
if (entry % 2 == 0)
list.Add(entry + 1);
Console.Write(entry + ", ");
}
Console.Write(list);
}
Output of last example:
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 1, 3, 5, 7, 9,
List (15 items)
0
1
2
3
4
5
6
7
8
9
1
3
5
7
9
As mentioned, but with a code sample:
foreach(var item in collection.ToArray())
collection.Add(new Item...);
You should really use for() instead of foreach() in this case.
You can't change the enumerable collection while it is being enumerated, so you will have to make your changes before or after enumerating.
The for loop is a nice alternative, but if your IEnumerable collection does not implement ICollection, it is not possible.
Either:
1) Copy collection first. Enumerate the copied collection and change the original collection during the enumeration. (#tvanfosson)
or
2) Keep a list of changes and commit them after the enumeration.
LINQ is very effective for juggling with collections.
Your types and structure are unclear to me, but I will try to fit your example to the best of my ability.
From your code it appears that, for each item, you are adding to that item everything from its own 'Enumerable' property. This is very simple:
foreach (var item in Enumerable)
{
item = item.AddRange(item.Enumerable));
}
As a more general example, let's say we want to iterate a collection and remove items where a certain condition is true. Avoiding foreach, using LINQ:
myCollection = myCollection.Where(item => item.ShouldBeKept);
Add an item based on each existing item? No problem:
myCollection = myCollection.Concat(myCollection.Select(item => new Item(item.SomeProp)));
Here's how you can do that (quick and dirty solution. If you really need this kind of behavior, you should either reconsider your design or override all IList<T> members and aggregate the source list):
using System;
using System.Collections.Generic;
namespace ConsoleApplication3
{
public class ModifiableList<T> : List<T>
{
private readonly IList<T> pendingAdditions = new List<T>();
private int activeEnumerators = 0;
public ModifiableList(IEnumerable<T> collection) : base(collection)
{
}
public ModifiableList()
{
}
public new void Add(T t)
{
if(activeEnumerators == 0)
base.Add(t);
else
pendingAdditions.Add(t);
}
public new IEnumerator<T> GetEnumerator()
{
++activeEnumerators;
foreach(T t in ((IList<T>)this))
yield return t;
--activeEnumerators;
AddRange(pendingAdditions);
pendingAdditions.Clear();
}
}
class Program
{
static void Main(string[] args)
{
ModifiableList<int> ints = new ModifiableList<int>(new int[] { 2, 4, 6, 8 });
foreach(int i in ints)
ints.Add(i * 2);
foreach(int i in ints)
Console.WriteLine(i * 2);
}
}
}
To add to Timo's answer LINQ can be used like this as well:
items = items.Select(i => {
...
//perform some logic adding / updating.
return i / return new Item();
...
//To remove an item simply have logic to return null.
//Then attach the Where to filter out nulls
return null;
...
}).Where(i => i != null);
The best approach from a performance perspective is probably to use a one or two arrays. Copy the list to an array, do operations on the array, and then build a new list from the array. Accessing an array element is faster than accessing a list item, and conversions between a List<T> and a T[] can use a fast "bulk copy" operation which avoids the overhead associated accessing individual items.
For example, suppose you have a List<string> and wish to have every string in the list which starts with T be followed by an item "Boo", while every string that starts with "U" is dropped entirely. An optimal approach would probably be something like:
int srcPtr,destPtr;
string[] arr;
srcPtr = theList.Count;
arr = new string[srcPtr*2];
theList.CopyTo(arr, theList.Count); // Copy into second half of the array
destPtr = 0;
for (; srcPtr < arr.Length; srcPtr++)
{
string st = arr[srcPtr];
char ch = (st ?? "!")[0]; // Get first character of string, or "!" if empty
if (ch != 'U')
arr[destPtr++] = st;
if (ch == 'T')
arr[destPtr++] = "Boo";
}
if (destPtr > arr.Length/2) // More than half of dest. array is used
{
theList = new List<String>(arr); // Adds extra elements
if (destPtr != arr.Length)
theList.RemoveRange(destPtr, arr.Length-destPtr); // Chop to proper length
}
else
{
Array.Resize(ref arr, destPtr);
theList = new List<String>(arr); // Adds extra elements
}
It would have been helpful if List<T> provided a method to construct a list from a portion of an array, but I'm unaware of any efficient method for doing so. Still, operations on arrays are pretty fast. Of note is the fact that adding and removing items from the list does not require "pushing" around other items; each item gets written directly to its appropriate spot in the array.
I have written one easy step, but because of this performance will be degraded
Here is my code snippet:-
for (int tempReg = 0; tempReg < reg.Matches(lines).Count; tempReg++)
{
foreach (Match match in reg.Matches(lines))
{
var aStringBuilder = new StringBuilder(lines);
aStringBuilder.Insert(startIndex, match.ToString().Replace(",", " ");
lines[k] = aStringBuilder.ToString();
tempReg = 0;
break;
}
}

How do I loop through items in a list box and then remove those item?

I'm getting the error below when trying to loop through a listbox and then remove the item.
List that this enumerator is bound to has been modified. An enumerator can only be used if the list does not change.
foreach (string s in listBox1.Items)
{
MessageBox.Show(s);
//do stuff with (s);
listBox1.Items.Remove(s);
}
How can I remove the item and still loop through the contents?
Do you want to remove all items? If so, do the foreach first, then just use Items.Clear() to remove all of them afterwards.
Otherwise, perhaps loop backwards by indexer:
listBox1.BeginUpdate();
try {
for(int i = listBox1.Items.Count - 1; i >= 0 ; i--) {
// do with listBox1.Items[i]
listBox1.Items.RemoveAt(i);
}
} finally {
listBox1.EndUpdate();
}
Everyone else has posted "going backwards" answer, so I'll give the alternative: create a list of items you want to remove, then remove them at the end:
List<string> removals = new List<string>();
foreach (string s in listBox1.Items)
{
MessageBox.Show(s);
//do stuff with (s);
removals.Add(s);
}
foreach (string s in removals)
{
listBox1.Items.Remove(s);
}
Sometimes the "work backwards" method is better, sometimes the above is better - particularly if you're dealing with a type which has a RemoveAll(collection) method. Worth knowing both though.
Here my solution without going backward and without a temporary list
while (listBox1.Items.Count > 0)
{
string s = listBox1.Items[0] as string;
// do something with s
listBox1.Items.RemoveAt(0);
}
You have to go through the collection from the last item to the first. this code is in vb
for i as integer= list.items.count-1 to 0 step -1
....
list.items.removeat(i)
next
Jefferson is right, you have to do it backwards.
Here's the c# equivalent:
for (var i == list.Items.Count - 1; i >= 0; i--)
{
list.Items.RemoveAt(i);
}
How about:
foreach(var s in listBox1.Items.ToArray())
{
MessageBox.Show(s);
//do stuff with (s);
listBox1.Items.Remove(s);
}
The ToArray makes a copy of the list, so you don't need to worry about it changing the list while you are processing it.
while(listbox.Items.Remove(s)) ; should work, as well. However, I think the backwards solution is the fastest.
You can't make modification to the collection being iterated within the ForEach block.
A quick fix is to iterate over a copy of the collection. An easy way to make this copy is through the ArrayList constructor. The DataRowView objects in the copied collection will refer to, and be able to modify, the same underlying data as your code.
For Each item As DataRowView In New System.Collections.ArrayList(lbOrdersNeedToBeVoided.Items)
please read http://social.msdn.microsoft.com/Forums/en-AU/vbgeneral/thread/b4d1f649-d78a-4e5b-8ad8-1940e3379bed

Categories

Resources