C# Select vs SelectMany

As the Verb describes that this method is selecting values from some source. While Select genereates value per source object, SelectMany generates combined value per source object.

Okay lets make an example to understand this,

First we can define a Customer class with list of strings with their contact numbers,

class Customer
{
     public string Name { get; set; }
     public string Title { get; set; }
     public List<string> ContactNumbers { get; set; }
}

Then create 3 customers for selection,

List<Customer> customers = new List<Customer>() {
                new Customer { Name = "Ian", Title = "Mr", ContactNumbers = new List<string> { "45521152", "90555236", "9855215" } },
                new Customer { Name = "Alfred", Title = "Mr", ContactNumbers = new List<string> { "12556661", "15556731" } },
                new Customer { Name = "Lilly", Title = "Mrs", ContactNumbers = new List<string> { "3678452"} }
            };

We have 3 customers and 6 contact numbers total. Let’s write each contact number with traditional way.

static void Main(string[] args)
{
     List<Customer> customers = new List<Customer>() {
     new Customer { Name = "Ian", Title = "Mr", ContactNumbers = new List<string> { "45521152", "90555236", "9855215" } },
     new Customer { Name = "Alfred", Title = "Mr", ContactNumbers = new List<string> { "12556661", "15556731" } },
     new Customer { Name = "Lilly", Title = "Mrs", ContactNumbers = new List<string> { "3678452"} }
     };

     foreach (var customer in customers)
     {
        foreach(var number in customer.ContactNumbers)
        {
            Console.WriteLine($"{number}");
        }
     }
     Console.ReadKey();
}

And we have result of every contact number,

We have to use double foreach loop to achieve this. Let’s try using Select() to achieve the same result!

static void Main(string[] args)
{
    List<Customer> customers = new List<Customer>() {
    new Customer { Name = "Ian", Title = "Mr", ContactNumbers = new List<string>  { "45521152", "90555236", "9855215" } },
    new Customer { Name = "Alfred", Title = "Mr", ContactNumbers = new List<string> { "12556661", "15556731" } },
     new Customer { Name = "Lilly", Title = "Mrs", ContactNumbers = new List<string> { "3678452"} }
    };

    IEnumerable<List<string>> contactNumbers = customers.Select(x => x.ContactNumbers);
    foreach (var numbers in contactNumbers)
    {
       foreach(var number in numbers)
       {
            Console.WriteLine($"{number}");
       }
    }

    Console.ReadKey();
}

Still same result and we have used double foreach again! Select method provides projection. When we Select(x=> x.ContractNumbers), first it took the source object which is “Mr.Ian”. It add Mr.Ian to list’s first item then, add each contractnumbers to the first item as List.

Select() made a projection with given property name per source object!

But there is still double foreach. Let’s try SelectMany() and see if we can flatten this lists. At the end we just need List of Contract numbers right?

static void Main(string[] args)
{
     List<Customer> customers = new List<Customer>() {
     new Customer { Name = "Ian", Title = "Mr", ContactNumbers = new List<string> { "45521152", "90555236", "9855215" } },
     new Customer { Name = "Alfred", Title = "Mr", ContactNumbers = new List<string> { "12556661", "15556731" } },
     new Customer { Name = "Lilly", Title = "Mrs", ContactNumbers = new List<string> { "3678452"} }
    };

    IEnumerable<string> contactNumbers = customers.SelectMany(x => x.ContactNumbers);
    foreach (var numbers in contactNumbers)
    {
         Console.WriteLine($"{numbers}");
    }

    Console.ReadKey();
}

We have just used SelectMany with same projection property which is “ContractNumbers”. We need contract numbers in a single list from every source.

Yes! SelectMany() had combine at a single list for every contract number for every source!