My last post was an intro to Any and All – with this post I will weave Where into the mix. I’ll warn that some of this may seem personal preference, but this post is really about what constitutes effective and idiomatic LINQ. IMHO, without having some of these ideas about good LINQ and bad LINQ is a bit like a craftsman that doesn’t care about using a chisel when a screwdriver is appropriate.

### Filtered input feeding a LINQ operator

I wish I had a nickel for every time I’ve seen:

// ugh! don't do this:
items.Where(x => pred(x)).Any())

I like to think of LINQ as a pipeline that includes a *Where* like this as “filtered input feeding a LINQ operator.” If the no-argument LINQ operator fed by the *Where *also has an an overload with a single-argument predicate, then you can always use that rather than the more complex Where…Op, like so:

// do this!
items.Any(x => pred(x))

Besides being less code, it’s closer to the predicate-logic (there exists an x such that predicate) kind of language, it’s more declarative and it has a shorter pipeline chain. I think there are plenty of reasons to claim this is idiomatic & effective.

The operator doesn’t have to be just Any that is fed by Where – all of the LINQ operators that have predicate and no-predicate overloads work here: First, Last, Single, Count and of course Any.

Don’t do this: |
Do this: |

items.Where(x=>p(x).Any() |
items.Any(x=>p(x)) |

items.Where(x=>p(x).First() |
items.First(x=>p(x)) |

items.Where(x=>p(x).Count() |
items.Count(x=>p(x)) |

items.Where(x=>p(x).Last() |
items.Last(x=>p(x)) |

items.Where(x=>p(x).Single() |
items.Single(x=>p(x)) |

…and of course their “OrDefault” overloads where they exist.

*Where* Feeding a LINQ Operator That Has A Predicate

Similar to *Where* feeding a non-predicated operator, *Where* feeding a predicated operator is another case where I generally like to get rid of the Where and roll its predicate into the other operator – we’ll cover rolling *Where *into *All *separately because *All *is special.

Illustrating with Where…Any:

items.Where(x => p1(x)).Any(x => p2(x))

Rolling Where…Any into just Any:

items.Any(x => p1(x) && p2(x))

..but of course it works for First, Last, Count and Single. It doesn’t work for SkipWhile or TakeWhile because they will end up yielding values from the filtered sequence. Since *Any *and *All *are related, it may come as a surprise that in regard to combining *Where *with *All*, that…

### All is special!

But why is *All *special? Consider this:

items.Where(i => i != null).All(x => x.IsFoo)

What happens if all of the items are null? The above expression will be vacuously true. However, if we combined it like this:

// NOT EQUIVALENT! Don't do this!
items.All(x => x != null && x.IsFoo)

If you have an inkling about what the right thing to do is, hold off just a second. We will derive an equivalent expression using the relationship between *Any* and *All *from the previous post and the above to arrive at an elegant solution that is correct for all predicates. We can do this by adding a not to the entire expression, changing All to Any and negating All’s predicate, like so:

### General form of *Where* feeding *All*

items.Where(x => p1(x)).All(x => p2(x))

Let’s first convert this to an equivalent expression with *Any *instead of *All *:

!items.Where(x => p1(x)).Any(x => !p2(x))

From the previous section of this post, we know how to combine *Where* and *Any*; we delete *Where* and modify *Any*‘s predicate, combining the original *Where *predicate with *Any*‘s predicate by *AND*ing them like so:

!items.Any(x => p1(x) && !p2(x))

Now we’re ready to convert *Any *back to *All – *we do so exactly the same way we converted *All *to *Any *in our first step – we’ll also apply De Morgan’s Laws for negating *Any*’s predicate. In applying that we end up with the replacement rule we sat out to write (and now we know why All is special):

// yay! We have derived our replacement rule for Where..All
items.All(x => !p1(x) || p2(x))

So let’s go back to example that threw things off:

// the original
items.Where(x => x != null).All(x => x.IsFoo)
// transform for Where..All
items.All(x => x == null || x.IsFoo)

If items is empty – this is vacuously true. If items contains only nulls, this returns true. In fact, nulls won’t cause this construct to return false – it’s the nonnull values – if any of them is not an IsFoo, then this construct will return false. Woot! It checks out!

### Conclusion

With the exception of the positional predicates that Where supports, Where can always be rolled into *Single, First, Last, Any, All, Count *and the *OrDefault *overloads for first three operators (no love for *TakeWhile* and *SkipWhile*, they operate on and provide items from the filtered output of *Where*.) While I’m not dogmatic about this, it’s good to have this under your belt if you want to write the simplest LINQ possible.