wtorek, 22 kwietnia 2014

[C#|Visual Studio] LINQ: join

Łączenie dwóch kolekcji w LINQ można wykonać na kilka sposobów:
  • inner join
  • group join
  • left outer join
Podstawowy i najczęściej używany sposób to inner join, czyli po prostu zwykłe złączenie kolekcji, przy czym jeżeli istnieją elementy, które nie mają swoich odpowiedników w drugiej kolekcji, to zostaną pominięte.

internal class Team
{
    public int Id { get; set; }
    public string Name { get; set; }
}

internal class Player
{
    public int Id { get; set; }
    public int TeamId { get; set; }
    public string Name { get; set; }
}

//...

var teams = new Team[3];
for (int i = 0; i < teams.Length; i++)
{
    teams[i] = new Team(){Id = i};
}

teams[0].Name = "Liverpool";
teams[1].Name = "Chelsea";
teams[2].Name = "Arsenal";

var players = new Player[3];
for (int i = 1; i <= players.Length; i++)
{
    players[i-1] = new Player() { Id = i - 1, TeamId =  i};

}

players[0].Name = "Hazard";
players[1].Name = "Ramsey";
players[2].Name = "Rooney";

var inner = from player in players
            join team in teams on player.TeamId equals team.Id
            select new
            {
                player.Name,
                TeamName = team.Name
            };

Console.WriteLine("Inner join:");
foreach (var result in inner)
{
    Console.WriteLine("{0}, {1}", result.Name, result.TeamName);
}    

Wypisane zostaną tylko dwa elementy, te, których indeksy TeamId pokrywają się z identyfikatorami drużyn (player[0], player[1])

Group join to konstrukcja sprowadzająca wynik do niepłaskiej struktury przypominającej wynik operacji group by. Operacja ta związana jest ze słowem kluczowym into, a jej wynik jest typu IEnumerable<IEnumerable<T>>. Możemy na tym oczywiście wywołać select spłaszczający wyniki.

var group = from team in teams
            join player in players on team.Id equals player.TeamId
                into playersWithTeams
            select new { Key = team.Name, Count = playersWithTeams.Count() };

foreach (var item in group)
{
    Console.WriteLine("{0}, {1}", item.Key, item.Count);
}

Left outer join przydaje się tam, gdzie z jakichś powodów chcemy dostać wszystkie elementy z kolekcji będącej lewą stroną operacji. Problemem jest, jak przedstawić elementy, które nie mają swojego odpowiednika w kolekcji, będącej prawą stroną join-a. W takim przypadku LINQ dostarcza extension metodę DefaultIfEmpty<T>, gdzie możemy podać, jak ma wyglądać taki "sztuczny" element.

var outer = from player in players
            join team in teams on player.TeamId equals team.Id
                into playersWithTeams
            from item in playersWithTeams.DefaultIfEmpty(new Team() {Name = "<Empty>"})
            select new
                       {
                           item.Name,
                           Player = player.Name
                       };

foreach (var item in outer)
{
    Console.WriteLine("{1}, {0}", item.Name, item.Player);
}            

Zostaną wypisane wszystkie trzy elementy kolekcji players.

Brak komentarzy:

Prześlij komentarz