How can I use "Where" with an async predicate?

.net, async-await, c#-5.0, linq

Solution

I think one of the reasons nothing like this is in the framework is that there is lots of possible variations and each choice will be the right one under certain circumstances:

- Should the predicates execute in parallel, or in series?

- If they execute in parallel, should they all execute at once, or should the degree of parallelism be limited?

- If they execute in parallel, should the results be in the same order as the original collection, in the order of completion, or in undefined order?

- If they should be returned in the order of completion, should there be some way to (asynchronously) get the results as they complete? (This would require the change of return type from `Task<IEnumerable<T>>` to something else.)

You said you want the predicates to execute in parallel. In that case, the simplest choice is to execute them all at once and return them in the order of completion:

static async Task<IEnumerable<T>> Where<T>(
    this IEnumerable<T> source, Func<T, Task<bool>> predicate)
{
    var results = new ConcurrentQueue<T>();
    var tasks = source.Select(
        async x =>
        {
            if (await predicate(x))
                results.Enqueue(x);
        });
    await Task.WhenAll(tasks);
    return results;
}

You could then use it like this:

var filteredAddresses = await addresses.Where(MeetsCriteria);

Problem

I have an async predicate method like this: ``` private async Task<bool> MeetsCriteria(Uri address) { //Do something involving awaiting an HTTP request. } ``` Say I have a collection of `Uri`s: ``` var addresses = new[] { new Uri("http://www.google.com/"), new Uri("http://www.stackoverflow.com/") //etc. }; ``` I want to filter `addresses` using `MeetsCriteria`. I want to do this asynchronously; I want multiple calls to the predicate to run asynchronously, and I want to then wait for all of them to complete and produce the filtered result set. Unfortunately, LINQ doesn't appear to support asynchronous predicates, so something like this doesn't work: ``` var filteredAddresses = addresses.Where(MeetsCriteria); ``` Is there a similarly convenient way to do this?

Original source