Flatten a sequence of sequences into a single sequence (List<string> from List<Object> contains that List<string>)

Viewed 134

I'm trying to extract some Lists of strings into a single List. First I have this class

public class Client
{
  public string Name { get; set; }

  public List<string> ApiScopes { get; set; }
}

Thus I'm getting my response as a List<Client> and my intention is to take all Client's Scopes into a single List without Looping I've tried this by LINQ:

 var x = clients.Select(c=> c.AllowedScopes.Select(x => x).ToList()).ToList();

this returns a List<List<string>>, and I just want to get all this into one Distinct list of strings.

2 Answers

It sounds like you want SelectMany (which flattens a sequence of sequences into a single sequence), with Distinct as well if you need a list with each scope only appearing once even if it's present for multiple clients:

var scopes = clients.SelectMany(c => c.ApiScopes).Distinct().ToList();

This assumes that Client.ApiScopes is never null. If it might be null, you need a little bit more work:

var scopes = clients
    .SelectMany(c => ((IEnumerable<string>) c.ApiScopes) ?? Enumerable.Empty<string>())
    .Distinct()
    .ToList();

You can use SelectMany to flatten results :

var scopes=clients.SelectMany(client=>client.ApiScopes)
                  .Distinct()
                  .ToList();

This is equivalent to :

var scopes= ( from client in clients
              from scope in client.ApiScopes
              select scope
            )
            .Distinct()
            .ToList();
Related