I am aware that the yield keyword indicates that the method in which it appears is an iterator. I was just wondering how that works with something like List<T>.AddRange.
Let's use the below example:
static void Main()
{
foreach (int i in MyInts())
{
Console.Write(i);
}
}
public static IEnumerable<int> MyInts()
{
for (int i = 0; i < 255; i++)
{
yield return i;
}
}
So in the above example after each yield, a value is returned in the foreach loop in Main and is printed to the console.
If we change Main to this:
static void Main()
{
var myList = new List<int>();
myList.AddRange(MyInts());
}
how does that work? Does AddRange get called for each int returned by the yield statement or does it somehow wait for all 255 values before adding the entire range?
The implementation of AddRange will iterate over the IEnumerable input using the iterator's .MoveNext() method until all values have been produced by your yielding method. This can be seen here.
So myList.AddRange(MyInts()); is called once and its implementation forces MyInts to return all of it values before moving on.
AddRange exhausts all values of the iterator because of how is implemented, but the following hypothetic method would only evaluate the first value of the iterator:
public void AddFirst<T>(IEnumerable<T> collection)
{
Insert(collection.First());
}
An interesting experiment while you play around with this is to add a Console.WriteLine(i); line in your MyInts method to see when each number is generated.
Short answer: When you call AddRange, it will internally iterate every item in your IEnumerable and add to the list.
If you did something like this:
var myList = new List<int>();
myList.AddRange(MyInts());
foreach (int i in myList)
{
Console.Write(i);
}
Then your values would be iterated twice, from the start to the end:
Once when adding to your list
Then in your for loop
Playing a bit
Now, let's suppose you created your own extension method for AddRange like this:
public static IEnumerable<T> AddRangeLazily<T>(this ICollection<T> col, IEnumerable<T> values)
{
foreach (T i in values)
{
yield return i; // first we yield
col.Add(i); // then we add
}
}
Then you could use it like this:
foreach (int i in myList.AddRangeLazily(MyInts()))
{
Console.Write(i);
}
...and it would be iterated twice as well, without going from the start to the end both times. It would lazily add each value to the list/collection and at the same time allow you to do something else (like printing it to output) after every new item being added.
If you had some sort of logic to stop the adding to the list in the middle of the operation, this should be helpful somehow.
The downside if this AddRangeLazily is: values will only be added to the collection once you iterate over AddRangeLazily like my code sample. If you just do this:
var someList = new List<int>();
someList.AddRangeLazily(MyInts());
if (someList.Any())
// it wouldn't enter here...
...it won't add values at all. If you wanted that behaviour, you should use AddRange. Forcing the iterationg over AddRangeLazily method would work, though:
var someList = new List<int>();
someList.AddRangeLazily(MyInts());
if (someList.AddRangeLazily(MyInts()).Count())
// it would enter here...thus adding all values to the someList
...however, depending on how lazy is the method you calling, it wouldn't iterate everything. For example:
var someList = new List<int>();
someList.AddRangeLazily(MyInts());
if (someList.AddRangeLazily(MyInts()).Any())
// it would enter here, plus adding only the first value to someList
Since Any() is true as soon as any item exists, then Any() just needs one iterationg to return true, therefore it just needs the first item to be iterated over.
I actually don't remember having to do something like this, it was just to play around with yield.
Fiddle here!!!
Interesting question.
The behavior is different if the enumerable is for a class that implements ICollection, such as another list or an array, but let's say it doesn't since your example doesn't. AddRange() simply uses the enumerator to insert items into the list one at a time.
using(IEnumerator<T> en = collection.GetEnumerator()) {
while(en.MoveNext()) {
Insert(index++, en.Current);
If the type of the enumerator is ICollection then AddRange first expands the list and then does a block copy.
If you want to see the code yourself:
https://referencesource.microsoft.com/#mscorlib/system/collections/generic/list.cs,51decd510e5bfe6e
Related
Why we can iterate item ex
mList.ForEach((item)
{
item.xyz ....
}
and for a simple array we need to force foreach loop?
foreach(int i in arr)
i.xyz
or use delegate type ?
Action<int> action = new Action<int>(myfunc);
Array.ForEach(intArray, action);
What is the differemce?
The first syntax is not correct. It should be like this:
mList.ForEach(item =>
{
// item.xyz
});
The ForEach is a method of List<T> that enables you for each item in a list to call an Action<T>.
On the other hand the foreach
statement repeats a group of embedded statements for each element in
an array or an object collection that implements the
System.Collections.IEnumerable or
System.Collections.Generic.IEnumerable interface.
That being said, ForEach can be called only on lists and foreach can be called on any object that implements either IEnumerable or IEnumerable. That's the big difference here.
Regarding the delegate type, there isn't any difference. Actually, lambda expressions item=>{ item.xyz = ...} are a shorthand for delegates.
The language defines foreach as an operation of IEnumerable. Therefore, everything which implements IEnumerable is iteratable. However, not all IEnumerables 'make sense' when using a ForEach block.
Take this for example:
public static IEnumerable<MyObject> GetObjects()
{
var i = 0;
while(i < 30)
yield return new MyObject { Name = "Object " + i++ };
}
And then you do something like this:
var objects = GetObjects();
objects.ForEach(o => o.Name = "Rob");
foreach (var obj in objects)
Console.WriteLine(obj.Name);
IF that compiled, it would print out Object 0 to Object 29 - NOT Rob 30 times.
The reason for this is that the iterator is reset each time you iterate the enumerable. It makes sense for ForEach on a list, as the enumerable has been materialized, and objects are not re-created every time you iterate it.
In order to make ForEach work on an enumerable, you'd need to materialize the collection as well (such as putting it into a list), but even that is not always possible, as you can have an enumerable with no defined end:
public static IEnumerable<MyObject> GetObjects()
{
while(true)
yield return new MyObject { Name = "Object " };
}
It also makes sense to have ForEach on Array - but for reasons I'm unaware of, it was defined as Array.ForEach(arr) rather than arr.ForEach()
Moral of the story is, if you think you need a ForEach block, you probably want to materialize the enumerable first, usually to a List<T> or an array (T[]).
I was wondering if there was a build in method to remove and return the first item of a list with one method/command.
I used this, which was not pretty
Item currentItem = items.First();
items.RemoveAt(0);
So I could wrote an extension-method:
public static class ListExtensions
{
public static T RemoveAndReturnFirst<T>(this List<T> list)
{
T currentFirst = list.First();
list.RemoveAt(0);
return currentFirst;
}
}
//Example code
Item currentItem = items.RemoveAndReturnFirst();
Is this the best possibility or is there any built-in method?
The list is returned from a nHibernate-Query and therefore it should remain a List<T>.
Most suitable collection for this operation is Queue:
var queue = new Queue<int>();
queue.Enqueue(10); //add first
queue.Enqueue(20); //add to the end
var first = queue.Dequeue(); //removes first and returns it (10)
Queue makes Enqueue and Dequeue operations very fast. But, if you need to search inside queue, or get item by index - it's bad choice. Compare, how many different types of operations do you have and according to this choose the most suitable collection - queue, stack, list or simple array.
Also you can create a Queue from a List:
var list = new List<int>();
var queue = new Queue<int>(list);
There is no built-in method. Your code looks fine to me.
One small thing, I would use the indexer, not the First extension method:
T currentFirst = list[0];
And check your list if there is a Count > 0.
public static T RemoveAndReturnFirst<T>(this List<T> list)
{
if (list == null || list.Count == 0)
{
// Instead of returning the default,
// an exception might be more compliant to the method signature.
return default(T);
}
T currentFirst = list[0];
list.RemoveAt(0);
return currentFirst;
}
If you have to worry about concurrency, I would advice to use another collection type, since this one isn't thread-safe.
I have this code:
public static void myMethodMytype paramObject, IEnumerable<MyType> paramObjects)
{
IEnumerable<Mytype> ieFilteredObjects = paramObjects.Where(x=>x.IDType == paramObject.IDType);
if (ieFilteredObjects.Count() == 2)
{
foreach (MyType iterator in ieFilteredObjects)
{
iterator.MyProperty = null;
}
}
}
In this case, ieFilteredObjects has 2 elements, but in the foreach, only update the first element, and the exit of the foreach.
If in the foreach I use this:
foreach (MyType iterator in ieFilteredObjects.ToList())
then it works as expected.
Why I have to convert the IEnumerable to a list?
Thanks.
IEnumerable can only be iterated once. You cannot iterate twice on an IEnumerable and expect to get the same values.
For instance, the IEnumerable may come from a yield return function, each time you call GetEnumerator() on the IEnumerable you start a new call to this function which may create new values.
This is not a common use case, but it exists. I already had this kind of bug in production.
The solution is to cache the result of the first iteration. A common technique is to use a linq: .ToList() to create a IList, that you can iterate ad infinitum
In your code you iterate at least twice:
ieFilteredObjects.Count()
foreach (MyType iterator in ieFilteredObjects)
First, I know this isn't possible out of the box because of obvious reasons.
foreach(string item in myListOfStrings) {
myListOfStrings.Remove(item);
}
The snipped above is one of the most horrible things I've ever seen. So, how do you achieve it then? You could iterate through the list backwards using for, but I don't like this solution either.
What I'm wondering is: Is there a method/extensions that returns an IEnumerable from the current list, something like a floating copy? LINQ has numerous extension methods that do exactly this, but you always have to do something with it, such as filtering (where, take...).
I'm looking forward to something like this:
foreach(string item in myListOfStrings.Shadow()) {
myListOfStrings.Remove(item);
}
where as .Shadow() is:
public static IEnumerable<T> Shadow<T>(this IEnumerable<T> source) {
return new IEnumerable<T>(source);
// or return source.Copy()
// or return source.TakeAll();
}
Example
foreach(ResponseFlags flag in responseFlagsList.Shadow()) {
switch(flag) {
case ResponseFlags.Case1:
...
case ResponseFlags.Case2:
...
}
...
this.InvokeSomeVoidEvent(flag)
responseFlagsList.Remove(flag);
}
Solution
This is how I solved it, and it works like a charm:
public static IEnumerable<T> Shadow<T>(this IEnumerable<T> source) where T: new() {
foreach(T item in source)
yield return item;
}
It's not that super fast (obviously), but it's safe and exactly what I intended to do.
Removing multiple elements from a list 1 by 1 is a C# anti-pattern due to how lists are implemented.
Of course, it can be done with a for loop (instead of foreach). Or it can be done by making a copy of the list. But here is why it should not be done. On a list of 100000 random integers, this takes 2500 ms on my machine:
foreach (var x in listA.ToList())
if (x % 2 == 0)
listA.Remove(x);
and this takes 1250 ms:
for (int i = 0; i < listA.Count; i++)
if (listA[i] % 2 == 0)
listA.RemoveAt(i--);
while these two take 5 and 2 ms respectively:
listB = listB.Where(x => x % 2 != 0).ToList();
listB.RemoveAll(x => x % 2 == 0);
This is because when you remove an element from a list, you are actually deleting from an array, and this is O(N) time, as you need to shift each element after the deleted element one position to the left. On average, this will be N/2 elements.
Remove(element) also needs to find the element before removing it. So Remove(element) will actually always take N steps - elementindex steps to find the element, N - elementindex steps to remove it - in total, N steps.
RemoveAt(index) doesn't have to find the element, but it still has to shift the underlying array, so on average, a RemoveAt is N/2 steps.
The end result is O(N^2) complexity either way, as you're removing up to N elements.
Instead, you should use Linq, which will modify the entire list in O(N) time, or roll your own, but you should not use Remove (or RemoveAt) in a loop.
Why not just do:
foreach(string item in myListOfStrings.ToList())
{
myListOfStrings.Remove(item);
}
To create a copy of the original and use for iterating, then remove from the existing.
If you really need your extension method you could perhaps create something more readable to the user such as:
public static IEnumerable<T> Shadow<T>(this IEnumerable<T> items)
{
if (items == null)
throw new NullReferenceException("Items cannot be null");
List<T> list = new List<T>();
foreach (var item in items)
{
list.Add(item);
}
return list;
}
Which is essentially the same as .ToList().
Calling:
foreach(string item in myListOfStrings.Shadow())
You do not LINQ extension methods for this - you can create a new list explicitly, like this:
foreach(string item in new List<string>(myListOfStrings)) {
myListOfStrings.Remove(item);
}
You have to create a copy of the original list while iterating as below:
var myListOfStrings = new List<string>();
myListOfStrings.Add("1");
myListOfStrings.Add("2");
myListOfStrings.Add("3");
myListOfStrings.Add("4");
myListOfStrings.Add("5");
foreach (string item in myListOfStrings.ToList())
{
myListOfStrings.Remove(item);
}
Your example removes all items from the string, so it's equivalent to:
myListOfStrings.Clear();
It is also equivalent to:
myListOfStrings.RemoveAll(x => true); // Empties myListOfStrings
But what I think you're looking for is a way to remove items for which a predicate is true - which is what RemoveAll() does.
So you could write, for example:
myListOfStrings.RemoveAll(x => x == "TEST"); // Modifies myListOfStrings
Or use any other predicate.
However, that changes the ORIGINAL list; If you just want a copy of the list with certain items removed, you can just use normal Linq:
// Note != instead of == as used in Removeall(),
// because the logic here is reversed.
var filteredList = myListOfStrings.Where(x => x != "TEST").ToList();
Picking up on the answer of svinja I do believe the most efficient way of solving this problem is by doing:
for (int i = 0; i < listA.Count;) {
if (listA[i] % 2 == 0)
listA.RemoveAt(i);
else
i++;
}
It improves on the answer by removing unnecessary sums and subtractions.
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.