Flipping a Boolean When All Values Meet a Condition with LINQ
Every once in a while, a seemingly simple coding problem can throw a chicken-or-egg situation at you. You’ve built complex software in mere hours, how can a for
loop throw you off like this…!?!?
Don’t worry, it happens…
Here’s a quick example: you want to loop through a collection and flip a boolean
if a condition is met by all of the elements in the collection.
So you try something like this:
public class Vector {
public float DX { get; set; }
public float DY { get; set; }
}
...
[Fact]
public void Flip_bool_on_collection_condition() {
var vectors = new List<Vector>() {
new Vector() {DX = 0.0f, DY = 0.0f},
new Vector() {DX = 1.0f, DY = 0.0f},
new Vector() {DX = 0.0f, DY = 0.0f},
new Vector() {DX = 1.0f, DY = 0.0f},
new Vector() {DX = 1.0f, DY = 0.0f}
};
bool myBool = false;
for (int i = 0; i < vectors.Count; i++) {
if (vectors[i].DX > 0) {
myBool = true;
}
else {
myBool = false;
}
}
_output.WriteLine("All vectors.DX > 0? " + myBool);
}
All vectors.DX > 0? True
myBool
is going to flick off and on until it reaches the last element. All vectors.DX > 0
is not True
it’s a lie!
It was probably obvious to you while you read the code, but what if you’ve been in a state of flow for 2 hours?… Goodbye flow…
Fight for your Flow
There are a few ways to make the code work the way you want it to, but there’s one that will help you stay in your flow because of its readability and brevity:
[Fact]
public void Flip_bool_on_collection_condition_1() {
var vectors = new List<Vector>() {
new Vector() {DX = 0.0f, DY = 0.0f},
new Vector() {DX = 1.0f, DY = 0.0f},
new Vector() {DX = 0.0f, DY = 0.0f},
new Vector() {DX = 1.0f, DY = 0.0f},
new Vector() {DX = 1.0f, DY = 0.0f}
};
bool myBool = vectors.All(vector => vector.DX > 0);
_output.WriteLine("All vectors.DX > 0? " + myBool);
}
All vectors.DX > 0? False
So:
[Fact]
public void Flip_bool_on_collection_condition() {
var vectors = new List<Vector>() {
new Vector() {DX = 1.0f, DY = 0.0f},
new Vector() {DX = 1.0f, DY = 0.0f},
new Vector() {DX = 1.0f, DY = 0.0f},
new Vector() {DX = 1.0f, DY = 0.0f},
new Vector() {DX = 1.0f, DY = 0.0f}
};
bool myBool = vectors.All(vector => vector.DX > 0);
_output.WriteLine("All vectors.DX > 0? " + myBool);
}
All vectors.DX > 0? True
We aren’t being lied to anymore. Enumerable.All is used to determine “whether all elements in a sequence satisfy a condition.”
Sure, we could have set myBool
to true
and flipped it to false
when we found an element that didn’t satisfy the condition. We could have also used break
to break out of the loop when we found the element.
I think the LINQ way is fine for our purpose here. It’s simple and clear what our intention is. It’s important to keep in mind that there are performance implications with LINQ. In a tight-loop situation, we want to avoid instantiating objects and excessive string manipulation inside the loop.
We also want to be aware that .All()
evaluates to true
for empty lists:
[Fact]
public void Flip_bool_on_collection_condition() {
var vectors = new List<Vector>() {
};
bool myBool = vectors.All(vector => vector.DX > 0);
_output.WriteLine("All vectors.DX > 0? " + myBool);
}
All vectors.DX > 0? True
So we can add a .Any()
to make sure there are elements in the list before we evaluate the condition:
[Fact]
public void Flip_bool_on_collection_condition() {
var vectors = new List() {
};
bool myBool = vectors.Any() && vectors.All(vector => vector.DX > 0);
_output.WriteLine("All vectors.DX > 0? " + myBool);
}
All vectors.DX > 0? False
Summary
We were perfectly fine in our flow when suddenly a little problem/solution tripped us up when we wrote our first pass on it. All we wanted to do was flip a bool if all the elements in a collection met a condition.
Luckily, LINQ .All()
rescued us with a simple and clear solution to meet the requirement. We have to be aware of the performance implications if we are doing something more complex inside the LINQ statement so that memory doesn’t get away from us. We also need to be aware that .All()
evaluates to true
for empty lists. Adding .Any()
to make sure there are elements in the list covers that case.
As always, thanks for reading! Make sure you sign up for my newsletter so you get these sent right to your inbox!
Related Posts:
- 3 Ways to Loop Without do/do-while/for/foreach/etc…
- Why Delegates? Why not Call Methods Directly?
- Bad Data, Try/Catch, and Slow Performance
- Singleton Indexer - A Workaround for not having Static Indexers in C#
- Calculating Values using Calculated Values in LINQ
- How to Map Nested JSON Objects to a .NET Dictionary
- Changing a Type within a Class when you Instantiate: An Intro to Generics
- What’s the Point of the ‘dynamic’ Primitive Type?…
- What Needs to Be Disposed?
- Throwing an Invalid Cast Exception?… Look Out for Unboxing