(line of code of interest is the last one, the rest is just for a full representation)
Using the following code, I wanted to take VOTERS until I exceeded the maximum votes needed, but it stops right before reaching that maximum number of votes, so my voters pool has 1 fewer voter than I wanted.
Is there a clean way in LINQ where I could have made it take votes UNTIL it reached the maximum numbers of votes? I know I could add one more voter or do this in a loop but I am curious if there was a good way to do this with LINQ instead.
var voters = new List<Person>
{
new Person("Alice", Vote.Yes ),
new Person("Bob", Vote.Yes),
new Person("Catherine", Vote.No),
new Person("Denzel", Vote.Yes),
new Person("Einrich", Vote.Abstain),
new Person("Frederica", Vote.Abstain),
new Person("Goeffried", Vote.Abstain),
};
voters.Single(c => c.Name == "Alice").Voices = 100;
voters.Single(c => c.Name == "Bob").Voices = 150;
voters.Single(c => c.Name == "Catherine").Voices = 99;
voters.Single(c => c.Name == "Denzel").Voices = 24;
voters.Single(c => c.Name == "Einrich").Voices = 52;
voters.Single(c => c.Name == "Frederica").Voices = 39;
voters.Single(c => c.Name == "Goeffried").Voices = 99;
// this takes voters until we are BEFORE reaching X voices...
int voicesSoFar = 0;
int voicesNeeded = 300;
var eligibleVoters = voters.TakeWhile((p => (voicesSoFar += p.Voices) < voicesNeeded ));
TakeWhile method:The TakeWhile (Func...) will return elements starting from the beginning of an IEnumerable collection until it satisfies the condition specified. If the condition is false then it will return the collection immediately. Example I: int[] numbers = { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 };
The TakeWhile<TSource>(IEnumerable<TSource>, Func<TSource,Boolean>) method tests each element of source by using predicate and yields the element if the result is true . Enumeration stops when the predicate function returns false for an element or when source contains no more elements.
C# Queryable Take() MethodGet specified number of elements from the beginning using the Take() method. The following is our array. int[] marks = { 35, 72, 50, 90, 95, 85, 52, 67 }; Now, use OrderByDescending to order the elements in Descending order. Then use the Take() method to get the elements.
In a situation where I wanted to execute a function until and including it hit an end condition I did:
public static IEnumerable<T> TakeUntilIncluding<T>(this IEnumerable<T> list, Func<T, bool> predicate)
{
foreach(T el in list)
{
yield return el;
if (predicate(el))
yield break;
}
}
Worked for me! I think this is an implementation-agnostic solution like Jason's, but simpler.
You're looking for
voters.TakeWhile(p => {
bool exceeded = voicesSoFar > voicesNeeded ;
voicesSoFar += p.Voices;
return !exceeded;
});
If you insist on a one-liner, this will work by comparing the previous value:
voters.TakeWhile(p => (voicesSoFar += p.Voices) - p.Voices < voicesNeeded);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With