Programing

Select와 SelectMany의 차이점

lottogame 2020. 9. 28. 07:50
반응형

Select와 SelectMany의 차이점


나는 사이의 차이를 검색했습니다 SelectSelectMany하지만 적절한 답을 찾을 수 없어. LINQ To SQL을 사용할 때 차이점을 알아야하지만 내가 찾은 것은 표준 배열 예제뿐입니다.

누군가 LINQ To SQL 예제를 제공 할 수 있습니까?


SelectMany목록 목록을 반환하는 쿼리를 평면화합니다. 예를 들면

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 });

.NET Fiddle의 라이브 데모


많은 것을 선택하는 것은 교차 곱을 취하는 SQL의 교차 조인 작업 과 같습니다 .
예를 들어 우리가

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

많은 것을 선택하여 다음 세트를 얻을 수 있습니다.

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

여기서 우리는 집합 A와 집합 B의 요소에서 만들 수있는 모든 가능한 조합을 취합니다.

다음은 시도해 볼 수있는 LINQ 예제입니다.

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 });

믹스에는 다음과 같은 평면 구조의 요소가 있습니다.

{(10,cat), (10,dog), (10,donkey), (20,cat), (20,dog), (20,donkey)}

여기에 이미지 설명 입력

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. 알바
  3. 코스타
  4. 별장
  5. Busquets

...


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.


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.


I understand SelectMany to work like a join shortcut.

So you can:

var orders = customers
             .Where(c => c.CustomerName == "Acme")
             .SelectMany(c => c.Orders);

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.


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

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.


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)

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'

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();

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.

참고URL : https://stackoverflow.com/questions/958949/difference-between-select-and-selectmany

반응형