LINQ - Realizando junções cruzadas (cross join) com LINQ to Objects


 Uma junção cruzada, também conhecida como um produto cartesiano, junta duas sequências de valores para criar uma nova coleção em que cada par combinado possível é representado. Ao usar a Language-Integrated Query (LINQ), a junção cruzada pode substituir loops aninhados.

A LINQ suporta dois tipos de junção principais : 

  1. Inner Joins - São realizadas usando operador Join ou a palavra-chave join quando usando a sintaxe de expressão de consulta. Essa junção encontra todos os itens em uma sequência que correspondem com os de uma segunda coleção baseada em seletores de chave. Cada combinação de itens com as chaves correspondentes é projetada em uma nova coleção. Isso significa que os elementos de cada conjunto podem ser representados, uma vez, várias vezes ou nunca nos resultados.
     
  2. Left outer joins - Neste caso cada item na primeira coleção será apresentado nos resultados mesmo se não houver uma chave correspondente na segunda sequência. É possível que itens na primeira coleção sejam usados para produzir múltiplos resultados onde a chave de seleção gera mais de uma correspondência.

Outro tipo de junção suporta pela LINQ é a junção cruzada (cross join) ou Produto Cartesiano. Neste caso ao combinar duas sequências usando esta abordagem cada item na primeira coleção é combinado com cada item na segunda coleção.

Nenhuma chave de seleção é requerida pois não há nenhuma filtragem de dados. A sequência resultante terá sempre o número de itens igual ao produto dos tamanhos das duas sequências originais.

Vamos mostrar neste artigo como realizar junções cruzadas com LINQ.

Recursos usados:

Nota: Baixe e use a versão Community 2015 do VS ela é grátis e é equivalente a versão Professional.

Criando a solução no VS 2015

Abra o VS Community 2015 e clique em New Project;

Selecione a Other Projects Type -> Visual Studio Solution e marque Blank Solution;

No menu File clique em Add -> New Project e inclua um projeto usando a linguagem C# e outro usando a linguagem VB .NET do tipo Console Application.

Assim teremos dois projetos onde iremos definir o código da nossa consulta de junção cruzada.

Usando a sintaxe de expressão de consulta

Executar uma junção cruzada com sintaxe de expressão de consulta do LINQ é simplesmente um caso de incluir duas cláusulas from : uma para cada sequência fonte.  Em seguida, adicionamos uma projeção usando a palavra-chave select. O código permanece conciso, enquanto que a intenção é muito clara, dando boa legibilidade e facilidade de manutenção.

O exemplo a seguir demonstra uma consulta de junção cruzada onde temos temos oito letras, que representam as colunas de um tabuleiro de xadrez. A segunda coleção tem oito dígitos para linhas tabuleiro.

Quando combinamos as duas sequências usando uma junção cruzada, geramos sessenta e quatro coordenadas; um para cada um dos quadrados do tabuleiro de xadrez.

O código VB .NET e CSharp definido em uma aplicação do tipo Console Application é mostrado abaixo:

Module Module1
    Sub Main()
        Dim letras As Char() = "ABCDEFGH".ToCharArray()
        Dim digitos As Char() = "12345678".ToCharArray()
        Dim coordenadas = From l In letras
                                        From d In digitos
                                        Select l.ToString() + d
        For Each coord In coordenadas
            Console.Write("{0} ", coord)
            If coord.EndsWith("8") Then
                Console.WriteLine()
            End If
        Next
        Console.ReadKey()
    End Sub
End Module

 

using System;
using System.Linq;
namespace CSharp_LINQ_juncao_cruzada
{
    class Program
    {
        static void Main(string[] args)
        {
            char[] letras = "ABCDEFGH".ToCharArray();
            char[] digitos = "12345678".ToCharArray();
            var coordenadas =
                             from l in letras
                             from d in digitos
                             select l.ToString() + d;
            foreach (var coord in coordendas)
            {
                Console.Write("{0} ", coord);
                if (coord.EndsWith("8"))
                {
                    Console.WriteLine();
                }
            }
        }
    }
}

 

VB .NET CSharp

O resultado obtido é mostrado a seguir:

Você pode notar pelo resultado que a primeira sequência da consulta é executada uma vez, ao passo que a segunda sequência, contendo os dígitos, é repetida para cada letra. É importante perceber que a segunda sequência será enumerada uma vez para cada item da primeira sequência.

Usando os operadores de consulta padrão

Para alcançar os mesmos resultados usando os operadores de consulta padrão podemos usar o operador SelectMany. Normalmente usaríamos esse método de extensão para realizar uma projeção um-para-muitos para uma sequência plana.

O método SelectMany - Projeta cada elemento de uma sequência a IEnumerable(Of T) e mesclar as sequências resultantes em uma sequência.

Esse método é implementado usando a execução diferida.O valor de retorno imediato é um objeto que armazena todas as informações
necessárias para executar a ação.
A consulta representada por esse método não é executada até que o objeto seja enumerado chamando
o método de GetEnumerator diretamente ou usando foreach em Visual C# ou For Each em Visual Basic.

Por exemplo, você pode ter uma coleção de membros de uma equipe, com cada objeto na seqüência contendo uma lista de habilidades que cada pessoa possui.  Com SelectMany, você poderia criar uma nova seqüência contendo as habilidades combinadas de todos os membros da equipe.

Para realizar a junção cruzada usaríamos o operador SelectMany contra a primeira sequência, e, onde normalmente, você usaria uma expressão lambda para especificar qual itens filhos retornar, você fornece uma expressão lambda que seleciona os itens da segunda sequência. Isso significa que todos os itens na segunda coleção são selecionados uma vez para cada item na primeira sequência.

A linha de código a seguir produz o mesmo resultado obtido no exemplo do tabuleiro de xadrez. A primeira expressão lambda obtêm os dígitos uma vez para cada letra e a segunda função combina a letra e o digito para cada um dos 64 resultados.

VB .NET
 
   var coordenadas = letras.SelectMany(l => digitos, (l, d) => l.ToString() + d);

 

CSharp
 
 Dim coordenadas = letras.SelectMany(Function(l) digitos, Function(l, d) l.ToString() + d)

 

Apenas para constar,  a seguir temos um trecho de código que usa laços foreach aninhados para obter o mesmo resultado sem utilizar uma consulta LINQ :

List<string> coordenadas = new List<string>();
foreach (char letra in letras)
{
    foreach (char digito in digitos)
    {
            coordenadas.Add(letra.ToString() + digito);
    }
}
 Dim coordenadas As New List(Of String)()

 For Each letra As Char In letras
            For Each digito As Char In digitos
                coordenadas.Add(letra.ToString() + digito)
            Next
 Next

 

Pegue o projeto completo aqui :  LINQ_juncao_cruzada.zip

Deus nunca foi visto por alguém. O Filho unigênito (Jesus), que está no seio do Pai, esse o revelou.
João 1:18

Veja os Destaques e novidades do SUPER DVD Visual Basic (sempre atualizado) : clique e confira !

Quer migrar para o VB .NET ?

Quer aprender C# ??

Quer aprender os conceitos da Programação Orientada a objetos ?

Quer aprender o gerar relatórios com o ReportViewer no VS 2013 ?

Quer aprender a criar aplicações Web Dinâmicas usando a ASP .NET MVC 5 ?

 

  Gostou ?   Compartilhe no Facebook   Compartilhe no Twitter

 

Referências:


José Carlos Macoratti