问题
I have the need to skip the first element that matches a predicate as a linq query. So far as I can tell the best I can do is something like this:
var list = new [] {1,2,3,4,5,6,7,8,9};
var skippedFirstOdd = false;
var skipFirstEvenNumber = list.SkipWhile(number =>
{
if(number % 2 != 0)
{
skippedFirst = true;
return true;
}
else
{
return false;
}
});
Which works (I think), but isn't very elegant. Is there a cleaner way to achieve this?
回答1:
You could write an iterator-block extension method:
public static IEnumerable<T> SkipFirstMatching<T>
(this IEnumerable<T> source, Func<T, bool> predicate)
{
if (source == null)
throw new ArgumentNullException("source");
if (predicate == null)
throw new ArgumentNullException("predicate");
return SkipFirstMatchingCore(source, predicate);
}
private static IEnumerable<T> SkipFirstMatchingCore<T>
(IEnumerable<T> source, Func<T, bool> predicate)
{
bool itemToSkipSeen = false;
foreach (T item in source)
{
if (!itemToSkipSeen && predicate(item))
itemToSkipSeen = true;
else yield return item;
}
}
And use it as:
var list = new [] { 1,2,3,4,5,6,7,8,9 };
var skipFirstEvenNumber = list.SkipFirstMatching(i => i % 2 == 0);
By the way, your current code doesn't seem correct at all. The variable is called skipFirstEvenNumber
, but the query is skipping odd numbers. Secondly, you appear to try to be using a side-effect to get the query to work, but you are only setting the flag variable, not reading it. Consequently, your current code should work just like a normal SkipWhile
.
EDIT: Made argument-validation eager.
来源:https://stackoverflow.com/questions/5310839/linq-skip-first-where-linq-to-objects