Since ForEach() method loop through all list members, Why can't I use a break/continue clause while I can use them inside a normal foreach loop
lstTemp.ForEach(i=>
{
if (i == 3)
break;
//do sth
}
);
Error:
"No enclosing loop out of which to
break or continue"
Because ForEach is a method and not a regular foreach loop. The ForEach method is there for simple tasks, if you need to break or continue just iterate over lstTemp with a regular foreach loop.
Usually, ForEach is implemented like this:
public static ForEach<T>(this IEnumerable<T> input, Action<T> action)
{
foreach(var i in input)
action(i);
}
As it is a normal method call, action doesn't know anything about the enclosing foreach, thus you can't break.
return will act as continue in ForEach.
Example:
var list = new List<int>() {1, 2, 3, 4};
list.ForEach(i =>
{
if (i == 3)
return;
Console.WriteLine(i);
}
);
Prints 1, 2, 4.
3 - skipped.
Presumably because you're using a lambda and the contents of the lambda are ignorant to the fact that it's being used inside a loop.
rather than using a break, perform a filter first like this (it may not be the exact filter you need, but illustrates the point)
lstTemp.Where(i => i!= 3).ForEach(i=> // do sth);
The way I'd explain it is this: ForEach is a method, not a language feature. The C# foreach construct is a feature of the language within which the other language constructs break and continue are permitted.
I would also point out (not trying to judge, just making an observation) that this is a good example of why some developers object to the use of a ForEach method: it doesn't really save typing in this simple case, it requires one more redirection than necessary, and it doesn't have all the functionality of foreach anyway.
In my opinion the main scenario in which a ForEach method makes sense is as an extension on IEnumerable<T>--to put at the end of a chain of method calls. It seems (to me) a bit strange that they added it to List<T>.
To iterate only part of the items and emulate the break perfectly, you can use FirstOrDefault:
lstTemp.FirstOrDefault(i=>
{
if (i == 3)
return true;
//do stuff
return false;
}
);
For list with 100000 items, if the 10th item is 3 it will iterate only 10 times, using the Where solution will work, but iterate the whole list first.
Because ForEach is a method and not a regular foreach loop is need iterate over lstTemp with a regular foreach loop in case break, but in case continue use return inside the ForEach method.
var lstTemp = new List<int>() {1, 2, 3, 4};
lstTemp.ForEach(i=>
{
if (i == 3) return;
//do sth
Console.WriteLine(i);
});
Output: 1, 2, 4
break and continue are C# language keywords that require compiler support. ForEach, to the C# compiler, is just a method.
Because you delegate an action for each item in the list.
i used it
list.ForEach((item) =>
{
if( isBreak == false ) do
{
if (isContinue)
break;
// TODO
} while (false); }
});
Related
Suppose I've an Arraylist(arr1) like the below
"String1 is present"
"String2 is present"
"String3 is present"
i wanted to see if 'String2' is present in this arraylist. i've done something like the below:
var containsstringmatch = arr1.OfType<string>().Any(arg=>arg.Contains("String2"));
if (containsstringmatch==true)
{
IEnumerable v1 = arr1.OfType<string>().Where(arg=>arg.Contains("String2"));
foreach (string s in v1)
{
st1 = s;
}
Console.WriteLine(st1);
}
which gives me the below output which is good:
"String2 is present"
I wanted to see if this can be achieved without me using the foreach loop. Can someone please provide suggestions as to how to do it.
Thanks
If you want only to print the first string that contains the search, you can use FirstOrDefault():
var foundString = arr1.OfType<string>().FirstOrDefault(arg => arg.Contains("String2"));
Console.WriteLine(string.IsNullOrEmpty(foundString) ? "Not found" : foundString);
Also, as Aomine wrote in his answer - ArrayLists where good when we worked with .Net 1.1. Since .Net 2.0 introduced generics, ArrayLists should be avoided.
As Rufus L wrote in his comment, your current code gets the last string containing the search string, not the first. If you want the last and not the first, you can simply use LastOrDefault instead of FirstOrDefault.
I'd avoid using ArrayList in this day and age in .NET, instead, favor the List<T> (if possible).
As for:
I wanted to see if this can be achieved without me using the foreach
loop.
if by this you mean that you want to avoid the foreach construct and perform everything inline:
arr1.OfType<string>()
.Where(arg => arg.Contains("String2"))
.ToList()
.ForEach(s => Console.WriteLine(s));
or if you just want to find the last element satisfying the said criteria:
var result = arr1.OfType<string>().LastOrDefault(arg => arg.Contains("String2"));
There is no way to do this without a foreach or for loop. But you can create an extension method that will move the code out of your method.
public static class ConsoleExtensions
{
public static void WriteToConsole(this IEnumerable<string> list)
{
foreach (string item in list)
Console.WriteLine(item);
}
}
usage:
arr1.OfType<string>().Where(arg=>arg.Contains("String2")).WriteToConsole();
I am little bit confused about loops in C#, What is best use cases for various loops like For, foreach, while, do while, List.ForEach?
Depends on the usecase. For example, if you want only the odd indexed items in an array, use a for loop with +2 in each run. ForEach is suitable for standard loops. But in some cases you cannot use one of them, e.g. in a foreach you cannot delete items from the collection. You need e.g. for in this case.
And, when you have a specific condition, you need a while loop.
You use for loop when you wanted to set a counter iteration such
for(int i=0;i<3;i++)//will loop until it meets the condition i<3
{ //statement here}
You use foreach if you are going to loop and display the collection of a variable such
string[] name = { "josh", "aj", "beard" };
// ... Loop with the foreach keyword.
foreach (string value in name)
{
Console.WriteLine(name);
}
while is use if you want to meet the condition first before the statement
while(condition)
{
//statement here
}
do while is use if you want to do the statement first before the condition
do
{
//statement here
}
while(condition)
I have the following piece of code which uses the foreach iterator.
foreach (var item in daysOfWeeksList)
{
daysOper |= item;
}
daysOfWeeksList is a list. I want to OR each item in the list and process the result?
This daysOfWeeksList is a
List<int> daysOfWeeksList
Say I wan to do something like this. The dosomething I want to do is the OR operation.
list.ForEach( item =>
{
item.DoSomething();
} );
How would you go about this using an foreach method available as part of the List collection? I got plenty of examples for this for 2 operands but not for a single operand.
Assuming daysOper starts as 0, I wouldn't use ForEach at all - I'd use Aggregate from LINQ:
var daysOper = daysOfWeekList.Aggregate((current, next) => current | next);
In other words, keep a running "current" value, and keep OR-ing it with the next value each time. (The result of one iteration will be used as the "current" value for the next iteration.)
In general, you want to use the Aggregate method for stuff like this where the standard aggragetors, like Sum don't fit.
(Edit: I assumed that the OP was doing the OR operation over a List. So I edited the below paragraph)
However, if DaysOfWeekList is a List, then have the opportunity to optimize performance by stopping at the first instance of "true". The Any method does this.
var result = daysOfWeekList.Any(daysOpr=>daysOpr);
If I use:
var strings = new List<string> { "sample" };
foreach (string s in strings)
{
Console.WriteLine(s);
strings.Add(s + "!");
}
the Add in the foreach throws an InvalidOperationException (Collection was modified; enumeration operation may not execute), which I consider logical, since we are pulling the rug from under our feet.
However, if I use:
var strings = new List<string> { "sample" };
strings.ForEach(s =>
{
Console.WriteLine(s);
strings.Add(s + "!");
});
it promptly shoots itself in the foot by looping until it throws an OutOfMemoryException.
This comes as a suprise to me, as I always thought that List.ForEach was either just a wrapper for foreach or for for.
Does anyone have an explanation for the how and the why of this behavior?
(Inpired by ForEach loop for a Generic List repeated endlessly)
It's because the ForEach method doesn't use the enumerator, it loops through the items with a for loop:
public void ForEach(Action<T> action)
{
if (action == null)
{
ThrowHelper.ThrowArgumentNullException(ExceptionArgument.match);
}
for (int i = 0; i < this._size; i++)
{
action(this._items[i]);
}
}
(code obtained with JustDecompile)
Since the enumerator is not used, it never checks if the list has changed, and the end condition of the for loop is never reached because _size is increased at every iteration.
List<T>.ForEach is implemented through for inside, so it does not use enumerator and it allows to modify the collection.
Because the ForEach attached to the List class internally uses a for loop that is directly attached to its internal members -- which you can see by downloading the source code for the .NET framework.
http://referencesource.microsoft.com/netframework.aspx
Where as a foreach loop is first and foremost a compiler optimization but also must operate against the collection as an observer -- so if the collection is modified it throws an exception.
We know about this issue, it was an oversight when it was originally written. Unfortunately, we can't change it because it would now prevent this previously working code from running:
var list = new List<string>();
list.Add("Foo");
list.Add("Bar");
list.ForEach((item) =>
{
if(item=="Foo")
list.Remove(item);
});
The usefulness of this method itself is questionable as Eric Lippert pointed out, so we didn't include it for .NET for Metro style apps (ie Windows 8 apps).
David Kean (BCL Team)
I have a loop that iterates through elements in a list. I am required to remove elements from this list within the loop based on certain conditions. When I try to do this in C#, I get an exception. apparently, it is not allowed to remove elements from the list which is being iterated through. The problem was observed with a foreach loop. Is there any standard way to get around this problem?
Note : One solution I could think of is to create a copy of the list solely for iteration purpose and to remove elements from the original list within the loop. I am looking for a better way of dealing with this.
When using List<T> the ToArray() method helps in this scenario vastly:
List<MyClass> items = new List<MyClass>();
foreach (MyClass item in items.ToArray())
{
if (/* condition */) items.Remove(item);
}
The alternative is to use a for loop instead of a foreach, but then you have to decrement the index variable whenever you remove an element i.e.
List<MyClass> items = new List<MyClass>();
for (int i = 0; i < items.Count; i++)
{
if (/* condition */)
{
items.RemoveAt(i);
i--;
}
}
If your list is an actual List<T> then you can use the built-in RemoveAll method to delete items based on a predicate:
int numberOfItemsRemoved = yourList.RemoveAll(x => ShouldThisItemBeDeleted(x));
You could use LINQ to replace the initial list by a new list by filtering out items:
IEnumerable<Foo> initialList = FetchList();
initialList = initialList.Where(x => SomeFilteringConditionOnElement(x));
// Now initialList will be filtered according to the condition
// The filtered elements will be subject to garbage collection
This way you don't have to worry about loops.
You can use integer indexing to remove items:
List<int> xs = new List<int> { 1, 2, 3, 4 };
for (int i = 0; i < xs.Count; ++i)
{
// Remove even numbers.
if (xs[i] % 2 == 0)
{
xs.RemoveAt(i);
--i;
}
}
This can be weird to read and tough to maintain, though, especially if the logic in the loop gets any more complex.
Another trick is to loop through the list backwards.. removing an item won't affect any of the items you are going to encounter in the rest of the loop.
I'm not recommending this or anything else though. Everything you need this for can probably be done using LINQ statements to filter the list on your requirements.
You can iterate with foreach this way:
List<Customer> custList = Customer.Populate();
foreach (var cust in custList.ToList())
{
custList.Remove(cust);
}
Note: ToList on the list of variables, this iterates through the list created by the ToList but removes the items from the original list.
Hope this helps.
The recommended solution is to put all your elements you want to remove in a separate list and after the first loop, put a second loop where you iterate over the remove-list and remove those elements form the first list.
The reason you get an error is because you're using a foreach loop. If you think about how a foreach loop works this makes sense. The foreach loop calls the GetEnumerator method on the List. If you where to change the number of elements in the List, the Enumerator the foreach loop holds wouldn't have the correct number of elements. If you removed an element a null exception error would be thrown, and if you added an element the loop would miss an item.
If you like Linq and Lamda expressions I would recommend Darin Dimitrov solution, otherwise I would use the solution provided by Chris Schmich.