is there a way to break out of the foreach extension method? The "break" keyword doesn't recognize the extension method as a valid scope to break from.
//Doesn't compile
Enumerable.Range(0, 10).ToList().ForEach(i => { System.Windows.MessageBox.Show(i.ToString()); if (i > 2)break; });
Edit: removed "linq" from question
note the code is just an example to show break not working in the extension method... really what I want is for the user to be able to abort processing a list.. the UI thread has an abort variable and the for loop just breaks when the user hits a cancel button. Right now, I have a normal for loop, but I wanted to see if it was possible to do with the extension method.
It's probably more accurate to call this a List<T> Foreach vs. a LINQ one.
In either case though no there is no way to break out of this loop. Primarily because it's not actually a loop per say. It's a method which takes a delegate that is called inside a loop.
Creating a ForEach with break capability is fairly straight forward though
public delegate void ForEachAction<T>(T value, ref bool doBreak);
public static void ForEach<T>(this IEnumerable<T> enumerable, ForEachAction<T> action) {
var doBreak = false;
foreach (var cur in enumerable) {
action(cur, ref doBreak);
if (doBreak) {
break;
}
}
}
You could then rewrite your code as the following
Enumerable.Range(0,10)
.ForEach((int i,ref bool doBreak) => {
System.Windows.MessageBox.Show(i.ToString());
if ( i > 2) {doBreak = true;}
});
I recommend using TakeWhile.
Enumerable.Range(0, 10).TakeWhile(i => i <= 2).ToList().ForEach(i => MessageBox.Show(i.ToString()));
Or, using Rx:
Enumerable.Range(0, 10).TakeWhile(i => i <= 2).Run(i => MessageBox.Show(i.ToString()));
Why not use Where?
Enumerable.Range(0, 10).Where(i => i <= 2).ToList().ForEach(...)
Try a "return" statement instead of "break"; it's a delegate function and not a real loop.
Try:
Enumerable.Range(0, 10).ToList().ForEach(i => { System.Windows.MessageBox.Show(i.ToString()); if (i > 2) return; });
For myself, I used Linq Select + FirstOrDefault. Transform "each" in the list but since we are asking for the First, it will stop transforming them after finding the first one that matches.
var thingOption = list.Select(thing => AsThingOption(thing))
.FirstOrDefault(option => option.HasValue) ?? Option.None<MyThing>;
As you can see I'm transforming each thing into an Option and my method AsThingOption may succeed at transforming and when it does we stop iterating over the list. If the conditions inside AsThingOption method never succeed at transforming, then end result is None.
Hope that helps!
Why not throw new Exception("Specific message") or use a boolean flag?
DataTable dt = new DataTable();
bool error = false;
try
{
dt.AsEnumerable().ToList().ForEach(dr =>
{
if (dr["Col1"].ToString() == "")
{
error = true;
throw new Exception("Specific message");
}
else
// Do something
});
}
catch (Exception ex)
{
if (ex.Message == "Specific message" || error)
// do something
else
throw ex;
}
I have a case where I need to loop actions until a condition is false and each action can modify the value used to track the condition. I came up with this variation of .TakeWhile(). The advantage here is that each item in the list can participate in some logic, then the loop can be aborted on a condition not directly related to the item.
new List<Action> {
Func1,
Func2
}.TakeWhile(action => {
action();
return _canContinue;
});
Related
var EXPEarners =
from victor in ins.BattleParticipants
where victor.GetComponent<TotalEXP>() != null
select victor;
foreach (GameObject victor in EXPEarners)
{
victor.GetComponent<TotalEXP>().value += EXPGain;
}
I'm new to LINQ and I would like some help. Is there a way to combine these two blocks of code so I don't have to call GetComponent() twice? (I'm using Unity.) Perhaps introduce a temporary variable and use a foreach loop instead? But the whole purpose of using LINQ was to avoid the foreach.
Also, is there a way to inject methods in between the LINQ statements, like call a void method before I select the final result, in case I want to do something "in between?"
There are a number of ways you could do this, but one small alteration to your query would get you to a single call:
First, get rid of the null check and simply return a map of victor and component:
var EXPEarners =
from victor in ins.BattleParticipants
select new {
victor,
component = victor.GetComponent<TotalEXP>()
};
Then, loop over each pair, adding the experience points if the component isn't null:
foreach (var participant in EXPEarners)
{
// can do something with participant.victor here
if (participant.component != null)
participant.component.value += EXPGain;
}
You could of course shorten this code up quite a bit, but if you do need to do something in between, you have the opportunity.
You could try this alternative:
// Dosomething for every item in the list
ins.BattleParticipants.All(gameObject => Reward(gameObject, EXPGain));
Then you write a method to perform "Reward", which can be as complex as you like
static bool Reward(GameObject gameObject, int EXPGain)
{
TotalEXP exp = gameObject.GetComponent<TotalEXP>();
if (exp != null)
{
exp.value += EXPGain;
return true;
}
return false;
}
And if you want, you can chain these, so for example you can also call a "Bonus" for all those you rewarded (where Reward returned true)
// Reward all EXPGain in the list then give them a Bonus
ins.BattleParticipants.Where(gameObject => Reward(gameObject, EXPGain)).All(gameObject => Bonus(gameObject, BONGain));
Then you write a method to perform "Bonus"
static bool Bonus(GameObject gameObject, int BONGain)
{
SomeOther soc = gameObject.GetComponent<SomeOther>();
if (soc != null)
{
soc.value += BONGain;
return true;
}
return false;
}
If you only want to increment TotalEXP value and you don't use a retrived GameObject somewhere else you can use let and retrive the collection of TotalEXP:
var TotalEXPs =
from victor in ins.BattleParticipants
let component = victor.GetComponent<TotalEXP>()
where component != null
select component;
foreach (TotalEXP expin TotalEXPs)
{
exp.value += EXPGain;
}
Otherwise, you can see #Cᴏʀʏ answer where you can retrive GameObject and it TotalEXP
Try searching for the "let" statement on LINQ. Maybe it can help you.
LINQ is like voodo magic to me. No need to show you what I've done, nothing works or even compiles, I'm just getting error in a somewhat not understandable language:
The type arguments for method 'System.Linq.Enumerable.SelectMany<TSource,TResult>(System.Collections.Generic.IEnumerable<TSource>, System.Func<TSource,int,System.Collections.Generic.IEnumerable<TResult>>)' cannot be inferred from the usage. Try specifying the type arguments explicitly.
So, here's my code:
foreach (string first in firstStrings)
foreach (string second in secondStrings)
{
try {
if (second.Contains(DoFormatting(first)))
DoStuff(first, second);
}
catch (Exception e)
{
LogStuff(first, second);
}
}
(How) can I translate it to Linq?
You could do the following to reduce it down to one foreach, but honestly you might as well leave it as is.
var pairs = from first in firstStrings
from second in secondStrings
select new
{
first,
second
};
foreach(var pair in pairs)
{
try
{
if (pair.second.Contains(DoFormatting(pair.first)))
DoStuff(pair.first, pair.second);
}
catch (Exception e)
{
LogStuff(pair.first, pair.second);
}
}
OR with extension methods
var pairs = firstStrings.Join(
secondStrings,
x=>true,
y=>true,
(first, second) => new { first, second});
foreach(var pair in pairs)
{
try
{
if (pair.second.Contains(DoFormatting(pair.first)))
DoStuff(pair.first, pair.second);
}
catch (Exception e)
{
LogStuff(pair.first, pair.second);
}
}
I would not use a ForEach extension method because enumerating over an enumeration and creating side effects is against the best practices of using Linq.
If you really want to you could create an extension method as below:
public static class ExtensionMethods
{
public static void ForEach<T>(this IEnumerable<T> enumeration, Action<T> action)
{
foreach (T item in enumeration)
{
action(item);
}
}
}
and then use LINQ as follows:
firstStrings.ForEach(first => secondStrings.ForEach(second =>
{
try
{
if (second.Contains(DoFormatting(first)))
{
DoStuff(first, second);
}
}
catch(Exception e)
{
LogStuff(first, second);
}
}));
But, as other commentors have mentioned, I would keep your code as is (at least in regard to whether you convert it to LINQ).
You can't really translate much of it to Linq because you still have to iterate over all of the permutation, which requires two separate nested loops.
You could do this, it doesn't save a lot, but some:
foreach (string first in firstStrings)
try {
foreach (var second in secondStrings.Where(second => second.Contains(DoFormatting(first))))
DoStuff(first, second);
}
catch (Exception e) {
LogStuff(first, second);
}
EDIT:
Note that the logging here would have to change because second is not available in the catch block, which is a problem with moving things to linq.. you have less access to which item in the collection caused the error. You would probably have to move the exception handling into both DoFormtting and DoStuff.
And, as juharr pointed out, if an exception is thrown it will terminate processing of secondStrings rather than continuing to the next. So that may not be the desired function either.. again, a side effect of moving to linq, you lose the ability to do fine grained exception handling and continuation.
The issue here is that LINQ was designed using principles of functional programming, and the big principle there is to not cause side effects.
That said there are some things you can do, using a combination of juharr and Erik's approaches
this would work:
var ContainedPairs=
firstStrings.Join(secondStrings,
x => true,
y => true,
(first, second) => new { first, second })
.Where(pairs => pairs.second.Contains(DoFormatting(pairs.first)));
//loop over pairs calling dostuff and error handling
Note that the important thing here is that DoFormatting must be guaranteed not to change pairs.first, and not to throw an error.
If this is not the case then changing the signature of DoFormatting to the following:
private bool ContainsFormatted(string first, string second, out Exception ex)
would allow you to do this:
var pairResults =
firstStrings.Join(secondStrings,
x => true,
y => true,
(first, second) => new { first, second })
.Select(pair =>
{
Exception ex = null;
var containsFormatted = ContainsFormatted(pair.second, pair.first, out ex);
return new { pair, containsFormatted, ex };
});
//loop over pair results, calling DoStuff on items where containsFormatted = true and logging exceptions etc otherwise
The point here is that side effects and error handling are still left out of linq, but that doesn't mean that you need to give up the benefits of a more functional style of programming
I would recommend taking a look at Lambda expressions.
http://msdn.microsoft.com/en-us/library/bb397675.aspx
So, the LINQ translation would look something like this
String result = second.Where( r => r.Contains(first));
I have a nested while loop inside a foreach loop where I would like to advance the enumerator indefinitately while a certain condition is met. To do this I try casting the enumerator to IEnumerator< T > (which it must be if it is in a foreach loop) then calling MoveNext() on the casted object but it gives me an error saying I cannot convert it.
Cannot convert type 'System.DateTime' to System.Collections.Generic.IEnumerator via a reference conversion, boxing conversion, unboxing conversion, wrapping conversion, or null type conversion.
foreach (DateTime time in times)
{
while (condition)
{
// perform action
// move to next item
(time as IEnumerator<DateTime>).MoveNext(); // will not let me do this
}
// code to execute after while condition is met
}
What is the best way to manually increment the IEnumerator inside of the foreach loop?
EDIT:
Edited to show there is code after the while loop that I would like executed once the condition is met which is why I wanted to manually increment inside the while then break out of it as opposed to continue which would put me back at the top. If this isn't possible I believe the best thing is to redesign how I am doing it.
Many of the other answers recommend using continue, which may very well help you do what you need to do. However, in the interests of showing manually moving the enumerator, first you must have the enumerator, and that means writing your loop as a while.
using (var enumerator = times.GetEnumerator())
{
DateTime time;
while (enumerator.MoveNext())
{
time = enumerator.Current;
// pre-condition code
while (condition)
{
if (enumerator.MoveNext())
{
time = enumerator.Current;
// condition code
}
else
{
condition = false;
}
}
// post-condition code
}
}
From your comments:
How can the foreach loop advance it if it doesn't implement the IEnumerator interface?
In your loop, time is a DateTime. It is not the object that needs to implement an interface or pattern to work in the loop. times is a sequence of DateTime values, it is the one that must implement the enumerable pattern. This is generally fulfilled by implementing the IEnumerable<T> and IEnumerable interfaces, which simply require T GetEnumerator() and object GetEnumerator() methods. The methods return an object implementing IEnumerator<T> and IEnumerator, which define a bool MoveNext() method and a T or object Current property. But time cannot be cast to IEnumerator, because it is no such thing, and neither is the times sequence.
You cannot modify the enumerator from inside the for loop. The language does not permit this. You need to use the continue statement in order to advance to the next iteration of a loop.
However, I'm not convinced that your loop even needs a continue. Read on.
In the context of your code you would need to convert the while to an if in order to make the continue refer to the foreach block.
foreach (DateTime time in times)
{
if (condition)
{
// perform action
continue;
}
// code to execute if condition is not met
}
But written like this it is clear that the following equivalent variant is simpler still
foreach (DateTime time in times)
{
if (condition)
{
// perform action
}
else
{
// code to execute if condition is not met
}
}
This is equivalent to your pseudo-code because the part marked code to execute after while condition is met is executed for each item for which condition is false.
My assumption in all of this is that condition is evaluated for each item in the list.
Perhaps you can use continue?
You would use the continue statement:
continue;
This is just a guess, but it sounds like what you're trying to do is take a list of datetimes and move past all of them which meet a certain criteria, then perform an action on the rest of the list. If that's what you're trying to do, you probably want something like SkipWhile() from System.Linq. For example, the following code takes a series of datetimes and skips past all of them which are before the cutoff date; then it prints out the remaining datetimes:
var times = new List<DateTime>()
{
DateTime.Now.AddDays(1), DateTime.Now.AddDays(2), DateTime.Now.AddDays(3), DateTime.Now.AddDays(4)
};
var cutoff = DateTime.Now.AddDays(2);
var timesAfterCutoff = times.SkipWhile(datetime => datetime.CompareTo(cutoff) < 1)
.Select(datetime => datetime);
foreach (var dateTime in timesAfterCutoff)
{
Console.WriteLine(dateTime);
}
Console.ReadLine();
Is that the sort of thing you're trying to do?
I definitely do not condone what I am about to suggest, but you can create a wrapper around the original IEnumerable to transform it into something that returns items which can be used to navigate the underlying the enumerator. The end result might look like the following.
public static void Main(string[] args)
{
IEnumerable<DateTime> times = GetTimes();
foreach (var step in times.StepWise())
{
while (condition)
{
step.MoveNext();
}
Console.WriteLine(step.Current);
}
}
Then we need to create our StepWise extension method.
public static class EnumerableExtension
{
public static IEnumerable<Step<T>> StepWise<T>(this IEnumerable<T> instance)
{
using (IEnumerator<T> enumerator = instance.GetEnumerator())
{
while (enumerator.MoveNext())
{
yield return new Step<T>(enumerator);
}
}
}
public struct Step<T>
{
private IEnumerator<T> enumerator;
public Step(IEnumerator<T> enumerator)
{
this.enumerator = enumerator;
}
public bool MoveNext()
{
return enumerator.MoveNext();
}
public T Current
{
get { return enumerator.Current; }
}
}
}
You could use a func as your iterator and keep the state that you are changing in that delegate to be evaluated each iteration.
public static IEnumerable<T> FunkyIEnumerable<T>(this Func<Tuple<bool, T>> nextOrNot)
{
while(true)
{
var result = nextOrNot();
if(result.Item1)
yield return result.Item2;
else
break;
}
yield break;
}
Func<Tuple<bool, int>> nextNumber = () =>
Tuple.Create(SomeRemoteService.CanIContinueToSendNumbers(), 1);
foreach(var justGonnaBeOne in nextNumber.FunkyIEnumerable())
Console.Writeline(justGonnaBeOne.ToString());
One alternative not yet mentioned is to have an enumerator return a wrapper object which allows access to itself in addition to the data element being enumerated. For sample:
struct ControllableEnumeratorItem<T>
{
private ControllableEnumerator parent;
public T Value {get {return parent.Value;}}
public bool MoveNext() {return parent.MoveNext();}
public ControllableEnumeratorItem(ControllableEnumerator newParent)
{parent = newParent;}
}
This approach could also be used by data structures that want to allow collections to be modified in controlled fashion during enumeration (e.g. by including "DeleteCurrentItem", "AddBeforeCurrentItem", and "AddAfterCurrentItem" methods).
Suppose I have a given object of type IEnumerable<string> which is the return value of method SomeMethod(), and which contains no repeated elements. I would like to be able to "zip" the following lines in a single LINQ query:
IEnumerable<string> someList = SomeMethod();
if (someList.Contains(givenString))
{
return (someList.Where(givenString));
}
else
{
return (someList);
}
Edit: I mistakenly used Single instead of First. Corrected now.
I know I can "zip" this by using the ternary operator, but that's just not the point. I would just list to be able to achieve this with a single line. Is that possible?
This will return items with given string or all items if given is not present in the list:
someList.Where(i => i == givenString || !someList.Contains(givenString))
The nature of your desired output requires that you either make two requests for the data, like you are now, or buffer the non-matches to return if no matches are found. The later would be especially useful in cases where actually getting the data is a relatively expensive call (eg: database query or WCF service). The buffering method would look like this:
static IEnumerable<T> AllIfNone<T>(this IEnumerable<T> source,
Func<T, bool> predicate)
{
//argument checking ignored for sample purposes
var buffer = new List<T>();
bool foundFirst = false;
foreach (var item in source)
{
if (predicate(item))
{
foundFirst = true;
yield return item;
}
else if (!foundFirst)
{
buffer.Add(item);
}
}
if (!foundFirst)
{
foreach (var item in buffer)
{
yield return item;
}
}
}
The laziness of this method is either that of Where or ToList depending on if the collection contains a match or not. If it does, you should get execution similar to Where. If not, you will get roughly the execution of calling ToList (with the overhead of all the failed filter checks) and iterating the result.
What is wrong with the ternary operator?
someList.Any(s => s == givenString) ? someList.Where(s => s == givenString) : someList;
It would be better to do the Where followed by the Any but I can't think of how to one-line that.
var reducedEnumerable = someList.Where(s => s == givenString);
return reducedEnumerable.Any() ? reducedEnumerable : someList;
It is not possible to change the return type on the method, which is what you're asking. The first condition returns a string and the second condition returns a collection of strings.
Just return the IEnumerable<string> collection, and call Single on the return value like this:
string test = ReturnCollectionOfStrings().Single(x => x == "test");
Imagine I have the following:
private IEnumerable MyFunc(parameter a)
{
using(MyDataContext dc = new MyDataContext)
{
return dc.tablename.Select(row => row.parameter == a);
}
}
private void UsingFunc()
{
var result = MyFunc(new a());
foreach(var row in result)
{
//Do something
}
}
According to the documentation the linq execution will defer till I actual enumerate the result, which occurs in the line at the foreach. However the using statement should force the object to be collected reliably at the end of the call to MyFunct().
What actually happens, when will the disposer run and/or the result run?
Only thing I can think of is the deferred execution is computed at compile time, so the actual call is moved by the compiler to the first line of the foreach, causing the using to perform correctly, but not run until the foreach line?
Is there a guru out there who can help?
EDIT: NOTE: This code does work, I just don't understand how.
I did some reading and I realised in my code that I had called the ToList() extension method which of course enumerates the result. The ticked answer's behaviour is perfectly correct for the actual question answered.
Sorry for any confusion.
I would expect that to simply not work; the Select is deferred, so no data has been consumed at this point. However, since you have disposed the data-context (before leaving MyFunc), it will never be able to get data. A better option is to pass the data-context into the method, so that the consumer can choose the lifetime. Also, I would recommend returning IQueryable<T> so that the consumer can "compose" the result (i.e. add OrderBy / Skip / Take / Where etc, and have it impact the final query):
// this could also be an instance method on the data-context
internal static IQueryable<SomeType> MyFunc(
this MyDataContext dc, parameter a)
{
return dc.tablename.Where(row => row.parameter == a);
}
private void UsingFunc()
{
using(MyDataContext dc = new MyDataContext()) {
var result = dc.MyFunc(new a());
foreach(var row in result)
{
//Do something
}
}
}
Update: if you (comments) don't want to defer execution (i.e. you don't want the caller dealing with the data-context), then you need to evaluate the results. You can do this by calling .ToList() or .ToArray() on the result to buffer the values.
private IEnumerable<SomeType> MyFunc(parameter a)
{
using(MyDataContext dc = new MyDataContext)
{
// or ToList() etc
return dc.tablename.Where(row => row.parameter == a).ToArray();
}
}
If you want to keep it deferred in this case, then you need to use an "iterator block":
private IEnumerable<SomeType> MyFunc(parameter a)
{
using(MyDataContext dc = new MyDataContext)
{
foreach(SomeType row in dc
.tablename.Where(row => row.parameter == a))
{
yield return row;
}
}
}
This is now deferred without passing the data-context around.
I just posted another deferred-execution solution to this problem here, including this sample code:
IQueryable<MyType> MyFunc(string myValue)
{
return from dc in new MyDataContext().Use()
from row in dc.MyTable
where row.MyField == myValue
select row;
}
void UsingFunc()
{
var result = MyFunc("MyValue").OrderBy(row => row.SortOrder);
foreach(var row in result)
{
//Do something
}
}
The Use() extension method essentially acts like a deferred using block.