SelectMany Anonymous Type and Skip Iterations

anonymous-types, c#, linq

Solution

You could return an empty `Enumerable<dynamic>`. Here's an example (though without your customers and `someCondition`, because I don't know what they are, but of the same general form of your example):

new int[] { 1, 2, 3, 4 }
    .AsParallel()
    .SelectMany(i => {
        if (i % 2 == 0)
            return Enumerable.Repeat(new { i, squared = i * i }, i);
        else
            return Enumerable.Empty<dynamic>();
        })
    .ToList();

So, with your objects and `someCondition`, it would look like

customers
    .AsParallel()
    .SelectMany(c => {
        var context = GetContextForCustomer(c);
        if (someCondition)
            return myData.Select(x => new { CustomerID = c, X1 = x.x1, X2 = x.x2 });
        else
            return Enumerable.Empty<dynamic>();
       })
    .ToList();

Problem

I've been trying for a long time to find a "clean" pattern to handle a `.SelectMany` with anonymous types when you don't always want to return a result. My most common use case looks like this: - We have a list of customers that I want to do reporting on. - Each customer's data resides in a separate database, so I do a parallel `.SelectMany` - In each lambda expression, I gather results for the customer toward the final report. - If a particular customer should be skipped, I need to return a empty list. - I whip these up often for quick reporting, so I'd prefer an anonymous type. For example, the logic may looks something like this: ``` //c is a customer var context = GetContextForCustomer(c); // look up some data, myData using the context connection if (someCondition) return myData.Select(x => new { CustomerID = c, X1 = x.x1, X2 = x.x2 }); else return null; ``` This could be implemented as a foreach statement: ``` var results = new List<WhatType?>(); foreach (var c in customers) { var context = GetContextForCustomer(c); if (someCondition) results.AddRange(myData.Select(x => new { CustomerID = c, X1 = x.x1, X2 = x.x2 })); } ``` Or it could be implemented with a `.SelectMany` that is pre-filtered with a `.Where`: ``` customers .Where(c => someCondition) .AsParallel() .SelectMany(c => { var context = GetContextForCustomer(c); return myData.Select(x => new { CustomerID = c, X1 = x.x1, X2 = x.x2 }); }) .ToList(); ``` There are problems with both of these approaches. The `foreach` solution requires initializing a `List` to store the results, and you have to define the type. The `.SelectMany` with `.Where` is often impractical because the logic for `someCondition` is fairly complex and depends on some data lookups. So my ideal solution would look something like this: ``` customers .AsParallel() .SelectMany(c => { var context = GetContextForCustomer(c); if (someCondition) return myData.Select(x => new { CustomerID = c, X1 = x.x1, X2 = x.x2 }); else continue? return null? return empty list? }) .ToList(); ``` What do I put in the `else` line to skip a return value? None of the solutions I can come up with work or are ideal: - `continue` doesn't compile because it's not an active `foreach` loop - `return null` causes an `NRE` - `return` empty list requires me to initialize a list of anonymous type again. Is there a way to accomplish the above that is clean, simple, and neat, and satisfies all my (picky) requirements?

Original source

Related problems