1337

I've been searching the difference between Select and SelectMany but I haven't been able to find a suitable answer. I need to learn the difference when using LINQ To SQL but all I've found are standard array examples.

Can someone provide a LINQ To SQL example?

Tarik
  • 79,711
  • 83
  • 236
  • 349
  • 9
    you can look at the code for SelectMany with one function, or with two functions http://referencesource.microsoft.com/#System.Core/System/Linq/Enumerable.cs,bc79a642e00b8681 – barlop Apr 30 '16 at 09:17
  • 1
    If you familiar with Kotlin it has quite similar implementations for collections as map aka C# Select and flatMap aka C# SelectMany. Basically Kotlin std library extension functions for collections has similarity to C# Linq library. – Arsenius Jun 14 '17 at 04:23
  • Would one agree that `SelectFromMany` would be a much more descriptive name than `SelectMany`? – misanthrop Apr 05 '22 at 12:31

20 Answers20

1930

SelectMany flattens queries that return lists of lists. For example

public class PhoneNumber
{
    public string Number { get; set; }
}

public class Person
{
    public IEnumerable<PhoneNumber> PhoneNumbers { get; set; }
    public string Name { get; set; }
}

IEnumerable<Person> people = new List<Person>();

// Select gets a list of lists of phone numbers
IEnumerable<IEnumerable<PhoneNumber>> phoneLists = people.Select(p => p.PhoneNumbers);

// SelectMany flattens it to just a list of phone numbers.
IEnumerable<PhoneNumber> phoneNumbers = people.SelectMany(p => p.PhoneNumbers);

// And to include data from the parent in the result: 
// pass an expression to the second parameter (resultSelector) in the overload:
var directory = people
   .SelectMany(p => p.PhoneNumbers,
               (parent, child) => new { parent.Name, child.Number });

Live Demo on .NET Fiddle

Graham
  • 7,431
  • 18
  • 59
  • 84
Mike Two
  • 44,935
  • 9
  • 80
  • 96
  • 1
    [Related question](http://stackoverflow.com/questions/6428940/how-to-flatten-nested-objects-with-linq-expression) on nesting SelectMany to flatten out a nested hierarchical structure. – Nate Anderson May 09 '17 at 15:41
  • 1
    To understand resultSelector more The below link helps http://blogs.interknowlogy.com/2008/10/10/use-linqs-selectmany-method-to-flatten-collections/ – jamir Jul 16 '19 at 11:52
  • 1
    One more demo with results from parent: https://dotnetfiddle.net/flcdCC – Evgenii Kosiakov Aug 21 '19 at 13:24
247

Select many is like cross join operation in SQL where it takes the cross product.
For example if we have

Set A={a,b,c}
Set B={x,y}

Select many can be used to get the following set

{ (x,a) , (x,b) , (x,c) , (y,a) , (y,b) , (y,c) }

Note that here we take the all the possible combinations that can be made from the elements of set A and set B.

Here is a LINQ example you can try

List<string> animals = new List<string>() { "cat", "dog", "donkey" };
List<int> number = new List<int>() { 10, 20 };

var mix = number.SelectMany(num => animals, (n, a) => new { n, a });

the mix will have following elements in flat structure like

{(10,cat), (10,dog), (10,donkey), (20,cat), (20,dog), (20,donkey)}
Uwe Keim
  • 39,551
  • 56
  • 175
  • 291
Sriwantha Attanayake
  • 7,694
  • 5
  • 42
  • 44
  • 6
    I know this is old, but I wanted to thank you for this, it saved me a lot! :) It can be useful to have a reference to those codes too: http://stackoverflow.com/questions/3479980/select-all-unique-combinations-of-a-single-list-with-no-repeats-using-linq Cheers! – user3439065 Jun 22 '14 at 14:12
  • 7
    SelectMany doesn't have to be used like that. It has an option to just take one function too. – barlop Apr 29 '16 at 16:46
  • 11
    I dunno if it's right to say that this is how `SelectMany` *is*. Rather, this is a way that `SelectMany` can be used, but is not actually the normal way of using it. – Dave Cousineau Oct 25 '17 at 16:53
  • 2
    This was the simplest answer for me to understand. – Chaim Eliyah Nov 07 '17 at 20:12
  • 1
    @ChaimEliyah it may well be the answer that you understood most easily, but if this were the only answer you read then I wouldn't expect that you actually understood what SelectMany() is doing; this doesn't at all represent what the function does in the general case - it just provides a particular (unusual) thing that it is *capable* of achieving. – Brondahl Jul 07 '22 at 15:14
155

enter image description here

var players = db.SoccerTeams.Where(c => c.Country == "Spain")
                            .SelectMany(c => c.players);

foreach(var player in players)
{
    Console.WriteLine(player.LastName);
}
  1. De Gea
  2. Alba
  3. Costa
  4. Villa
  5. Busquets

...

Lews Therin
  • 3,707
  • 2
  • 27
  • 53
AlejandroR
  • 5,133
  • 4
  • 35
  • 45
82

SelectMany() lets you collapse a multidimensional sequence in a way that would otherwise require a second Select() or loop.

More details at this blog post.

Sameer Alibhai
  • 3,092
  • 4
  • 36
  • 36
Michael Petrotta
  • 59,888
  • 27
  • 145
  • 179
  • But the first one return Enumerables type of Children the second example return type of Parents ? Actually I am little bit confused,would you open it up little bit more ? – Tarik Jun 06 '09 at 04:56
  • Other way around, actually. The second will completely flatten the hierarchy of enumerables, so that you get Children back. Try the article at the link I added, see if that helps. – Michael Petrotta Jun 06 '09 at 05:02
  • The first one does not appear to be legal. I think the poster got confused himself. The second one would return an enumerable of parents. – mqp Jun 06 '09 at 05:02
  • Thanks, well actually yeah the examples were kinda confusing tho :) but thanks again for trying to help me. – Tarik Jun 06 '09 at 05:22
40

There are several overloads to SelectMany. One of them allows you to keep trace of any relationship between parent and children while traversing the hierarchy.

Example: suppose you have the following structure: League -> Teams -> Player.

You can easily return a flat collection of players. However you may lose any reference to the team the player is part of.

Fortunately there is an overload for such purpose:

var teamsAndTheirLeagues = 
         from helper in leagues.SelectMany
               ( l => l.Teams
                 , ( league, team ) => new { league, team } )
                      where helper.team.Players.Count > 2 
                           && helper.league.Teams.Count < 10
                           select new 
                                  { LeagueID = helper.league.ID
                                    , Team = helper.team 
                                   };

The previous example is taken from Dan's IK blog. I strongly recommend you take a look at it.

Uwe Keim
  • 39,551
  • 56
  • 175
  • 291
roland
  • 7,695
  • 6
  • 46
  • 61
26

I understand SelectMany to work like a join shortcut.

So you can:

var orders = customers
             .Where(c => c.CustomerName == "Acme")
             .SelectMany(c => c.Orders);
Selim Yildiz
  • 5,254
  • 6
  • 18
  • 28
Nathan Koop
  • 24,803
  • 25
  • 90
  • 125
  • 4
    The provided example works, but **SelectMany** does not exactly work like a join. A join allows to "use" any field of the original table plus any field of the joined table. But here you have to specify an object of a list attached to the original table. For example, `.SelectMany(c => new {c.CompanyName, c.Orders.ShippedDate});` would not work. SelectMany is rather flattening the list of lists - and you can pick any (but only one at a time) of the contained lists for the result. For comparison: [Inner join in Linq](https://stackoverflow.com/a/37332/1016343). – Matt Apr 19 '18 at 08:33
23

The SelectMany() method is used to flatten a sequence in which each of the elements of the sequence is a separate.

I have class user same like this

class User
    {
        public string UserName { get; set; }
        public List<string> Roles { get; set; }
    }

main:

var users = new List<User>
            {
                new User { UserName = "Reza" , Roles = new List<string>{"Superadmin" } },
                new User { UserName = "Amin" , Roles = new List<string>{"Guest","Reseption" } },
                new User { UserName = "Nima" , Roles = new List<string>{"Nurse","Guest" } },
            };

var query = users.SelectMany(user => user.Roles, (user, role) => new { user.UserName, role });

foreach (var obj in query)
{
    Console.WriteLine(obj);
}
//output

//{ UserName = Reza, role = Superadmin }
//{ UserName = Amin, role = Guest }
//{ UserName = Amin, role = Reseption }
//{ UserName = Nima, role = Nurse }
//{ UserName = Nima, role = Guest }

You can use operations on any item of sequence

int[][] numbers = {
                new[] {1, 2, 3},
                new[] {4},
                new[] {5, 6 , 6 , 2 , 7, 8},
                new[] {12, 14}
            };

IEnumerable<int> result = numbers
                .SelectMany(array => array.Distinct())
                .OrderBy(x => x);

//output

//{ 1, 2 , 2 , 3, 4, 5, 6, 7, 8, 12, 14 }
 List<List<int>> numbers = new List<List<int>> {
                new List<int> {1, 2, 3},
                new List<int> {12},
                new List<int> {5, 6, 5, 7},
                new List<int> {10, 10, 10, 12}
            };

 IEnumerable<int> result = numbers
                .SelectMany(list => list)
                .Distinct()
                .OrderBy(x=>x);

//output

// { 1, 2, 3, 5, 6, 7, 10, 12 }
Reza Jenabi
  • 3,884
  • 1
  • 29
  • 34
  • What if one or more of the lists happen to be null, can you still aggregate the others? I'm getting an error because of having a couple of null results. – Rod Jul 15 '20 at 14:29
13

Select is a simple one-to-one projection from source element to a result element. Select- Many is used when there are multiple from clauses in a query expression: each element in the original sequence is used to generate a new sequence.

Alexandr
  • 5,460
  • 4
  • 40
  • 70
9

Some SelectMany may not be necessary. Below 2 queries give the same result.

Customers.Where(c=>c.Name=="Tom").SelectMany(c=>c.Orders)

Orders.Where(o=>o.Customer.Name=="Tom")

For 1-to-Many relationship,

  1. if Start from "1", SelectMany is needed, it flattens the many.
  2. if Start from "Many", SelectMany is not needed. (still be able to filter from "1", also this is simpler than below standard join query)

from o in Orders
join c in Customers on o.CustomerID equals c.ID
where c.Name == "Tom"
select o
Rm558
  • 4,621
  • 3
  • 38
  • 43
9

The formal description for SelectMany() is:

Projects each element of a sequence to an IEnumerable and flattens the resulting sequences into one sequence.

SelectMany() flattens the resulting sequences into one sequence, and invokes a result selector function on each element therein.

class PetOwner
{
    public string Name { get; set; }
    public List<String> Pets { get; set; }
}

public static void SelectManyEx()
{
     PetOwner[] petOwners =
         { new PetOwner { Name="Higa, Sidney",
              Pets = new List<string>{ "Scruffy", "Sam" } },
           new PetOwner { Name="Ashkenazi, Ronen",
              Pets = new List<string>{ "Walker", "Sugar" } },
           new PetOwner { Name="Price, Vernette",
              Pets = new List<string>{ "Scratches", "Diesel" } } };

// Query using SelectMany().
IEnumerable<string> query1 = petOwners.SelectMany(petOwner => petOwner.Pets);

Console.WriteLine("Using SelectMany():");

// Only one foreach loop is required to iterate
// through the results since it is a
// one-dimensional collection.
foreach (string pet in query1)
{
    Console.WriteLine(pet);
}

// This code shows how to use Select()
// instead of SelectMany().
IEnumerable<List<String>> query2 =
    petOwners.Select(petOwner => petOwner.Pets);

Console.WriteLine("\nUsing Select():");

// Notice that two foreach loops are required to
// iterate through the results
// because the query returns a collection of arrays.
foreach (List<String> petList in query2)
{
    foreach (string pet in petList)
    {
        Console.WriteLine(pet);
    }
    Console.WriteLine();
}
}

/*
   This code produces the following output:

    Using SelectMany():
    Scruffy
    Sam
    Walker
    Sugar
    Scratches
    Diesel

   Using Select():
   Scruffy
   Sam

   Walker
   Sugar

   Scratches
   Diesel
  */

The main difference is the result of each method while SelectMany() returns a flattern results; the Select() returns a list of list instead of a flattern result set.

Therefor the result of SelectMany is a list like

{Scruffy, Sam , Walker, Sugar, Scratches , Diesel}

which you can iterate each item by just one foreach. But with the result of select you need an extra foreach loop to iterate through the results because the query returns a collection of arrays.

nzrytmn
  • 6,193
  • 1
  • 41
  • 38
5

Just for an alternate view that may help some functional programmers out there:

  • Select is map
  • SelectMany is bind (or flatMap for your Scala/Kotlin people)
Matt Klein
  • 7,856
  • 6
  • 45
  • 46
4

Without getting too technical - database with many Organizations, each with many Users:-

var orgId = "123456789";

var userList1 = db.Organizations
                   .Where(a => a.OrganizationId == orgId)
                   .SelectMany(a => a.Users)
                   .ToList();

var userList2 = db.Users
                   .Where(a => a.OrganizationId == orgId)
                   .ToList();

both return the same ApplicationUser list for the selected Organization.

The first "projects" from Organization to Users, the second queries the Users table directly.

RickL
  • 3,318
  • 10
  • 38
  • 39
4

It's more clear when the query return a string (an array of char):

For example if the list 'Fruits' contains 'apple'

'Select' returns the string:

Fruits.Select(s=>s) 

[0]: "apple"

'SelectMany' flattens the string:

Fruits.SelectMany(s=>s)

[0]: 97  'a'
[1]: 112 'p'
[2]: 112 'p'
[3]: 108 'l'
[4]: 101 'e'
Eric Bole-Feysot
  • 13,949
  • 7
  • 47
  • 53
4

Consider this example :

        var array = new string[2]
        {
            "I like what I like",
            "I like what you like"
        };
        //query1 returns two elements sth like this:
        //fisrt element would be array[5]  :[0] = "I" "like" "what" "I" "like"
        //second element would be array[5] :[1] = "I" "like" "what" "you" "like"
        IEnumerable<string[]> query1 = array.Select(s => s.Split(' ')).Distinct();

        //query2 return back flat result sth like this :
        // "I" "like" "what" "you"
        IEnumerable<string> query2 = array.SelectMany(s => s.Split(' ')).Distinct();

So as you see duplicate values like "I" or "like" have been removed from query2 because "SelectMany" flattens and projects across multiple sequences. But query1 returns sequence of string arrays. and since there are two different arrays in query1 (first and second element), nothing would be removed.

  • probably better to now include .Distinct() at end and state it outputs "I" "like" "what" "I" "like" "I" "like" "what" "you" "like" – friartuck Apr 01 '20 at 22:57
3

The SelectMany method knocks down an IEnumerable<IEnumerable<T>> into an IEnumerable<T>, like communism, every element is behaved in the same manner(a stupid guy has same rights of a genious one).

var words = new [] { "a,b,c", "d,e", "f" };
var splitAndCombine = words.SelectMany(x => x.Split(','));
// returns { "a", "b", "c", "d", "e", "f" }
2

One more example how SelectMany + Select can be used in order to accumulate sub array objects data.

Suppose we have users with they phones:

class Phone { 
    public string BasePart = "555-xxx-xxx"; 
}

class User { 
    public string Name = "Xxxxx";
    public List<Phone> Phones; 
}

Now we need to select all phones' BaseParts of all users:

var usersArray = new List<User>(); // array of arrays
List<string> allBaseParts = usersArray.SelectMany(ua => ua.Phones).Select(p => p.BasePart).ToList();
KEMBL
  • 536
  • 6
  • 10
1

Suppose you have an array of countries

var countries = new[] { "France", "Italy" };

If you perform Select on countries, you will get each element of the array as IEnumerable<T>

IEnumerable<string> selectQuery = countries.Select(country => country);

In the above code, the country represents a string that refers to each country in the array. now iterate over selectQuery to get countries:

foreach(var country in selectQuery)
    Console.WriteLine(country);

// output
//
// France
// Italy

If you want to print every character of countries you have to use nested foreach

foreach (var country in selectQuery)
{
    foreach (var charOfCountry in country)
    {
        Console.Write(charOfCountry + ", ");
    }
}

// output

// F, r, a, n, c, e, I, t, a, l, y,

OK. now try to perform SelectMany on countries. This time SelectMany gets each country as string (as before) and because of string type is a collection of chars, SelectMany tries to divide each country into its constituent parts (chars) and then returns a collection of chars as IEnumerable<T>

IEnumerable<char> selectManyQuery = countries.SelectMany(country => country);

In the above code, the country represents a string that refers to each country in the array as before, but the return value is the chars of each country

Actually SelectMany likes to fetch two levels inside of collections and flatten the second level as IEnumerable<T>

Now iterate over selectManyQuery to get chars of each country:

foreach(var charOfCountry in selectManyQuery)
    Console.Write(charOfCountry + ", ");

// output

// F, r, a, n, c, e, I, t, a, l, y,
Hamid Mohammadi
  • 286
  • 1
  • 10
0

Here is a code example with an initialized small collection for testing:

class Program
{
    static void Main(string[] args)
    {
        List<Order> orders = new List<Order>
        {
            new Order
            {
                OrderID = "orderID1",
                OrderLines = new List<OrderLine>
                {
                    new OrderLine
                    {
                        ProductSKU = "SKU1",
                        Quantity = 1
                    },
                    new OrderLine
                    {
                        ProductSKU = "SKU2",
                        Quantity = 2
                    },
                    new OrderLine
                    {
                        ProductSKU = "SKU3",
                        Quantity = 3
                    }
                }
            },
            new Order
            {
                OrderID = "orderID2",
                OrderLines = new List<OrderLine>
                {
                    new OrderLine
                    {
                        ProductSKU = "SKU4",
                        Quantity = 4
                    },
                    new OrderLine
                    {
                        ProductSKU = "SKU5",
                        Quantity = 5
                    }
                }
            }
        };

        //required result is the list of all SKUs in orders
        List<string> allSKUs = new List<string>();

        //With Select case 2 foreach loops are required
        var flattenedOrdersLinesSelectCase = orders.Select(o => o.OrderLines);
        foreach (var flattenedOrderLine in flattenedOrdersLinesSelectCase)
        {
            foreach (OrderLine orderLine in flattenedOrderLine)
            {
                allSKUs.Add(orderLine.ProductSKU);
            }
        }

        //With SelectMany case only one foreach loop is required
        allSKUs = new List<string>();
        var flattenedOrdersLinesSelectManyCase = orders.SelectMany(o => o.OrderLines);
        foreach (var flattenedOrderLine in flattenedOrdersLinesSelectManyCase)
        {
            allSKUs.Add(flattenedOrderLine.ProductSKU);
        }

       //If the required result is flattened list which has OrderID, ProductSKU and Quantity,
       //SelectMany with selector is very helpful to get the required result
       //and allows avoiding own For loops what according to my experience do code faster when
       // hundreds of thousands of data rows must be operated
        List<OrderLineForReport> ordersLinesForReport = (List<OrderLineForReport>)orders.SelectMany(o => o.OrderLines,
            (o, ol) => new OrderLineForReport
            {
                OrderID = o.OrderID,
                ProductSKU = ol.ProductSKU,
                Quantity = ol.Quantity
            }).ToList();
    }
}
class Order
{
    public string OrderID { get; set; }
    public List<OrderLine> OrderLines { get; set; }
}
class OrderLine
{
    public string ProductSKU { get; set; }
    public int Quantity { get; set; }
}
class OrderLineForReport
{
    public string OrderID { get; set; }
    public string ProductSKU { get; set; }
    public int Quantity { get; set; }
}
Sharunas Bielskis
  • 1,033
  • 1
  • 16
  • 25
0

A select operator is used to select value from a collection and SelectMany operator is used to selecting values from a collection of collection i.e. nested collection.

-3

It is the best way to understand i think.

            var query =
            Enumerable
                .Range(1, 10)
                .SelectMany(ints => Enumerable.Range(1, 10), (a, b) => $"{a} * {b} = {a * b}")
                .ToArray();

        Console.WriteLine(string.Join(Environment.NewLine, query));

        Console.Read();

Multiplication Table example.