## GroupJoin
- A resultSelector função é chamada apenas uma vez para cada outer elemento junto com uma coleção de todos os inner elementos que correspondem ao outer elemento.
```csharp=
record Pessoa(string nome);
record Fruta(string nome, Pessoa dono);
Pessoa pedro = new Pessoa("Pedro");
Pessoa jorge = new Pessoa("Jorge");
Pessoa danilo = new Pessoa("Danilo");
Fruta abacaxi = new Fruta("Abacaxi", pedro);
Fruta maca = new Fruta("Maça", pedro);
Fruta banana = new Fruta("Banana", pedro);
Fruta morango = new Fruta("Morango", danilo);
List<Pessoa> pessoas = new List<Pessoa>() { pedro, jorge, danilo };
List<Fruta> frutas = new List<Fruta>() { abacaxi, maca, banana, morango };
var query = pessoas
.GroupJoin(frutas,
p => p,
f => f.dono,
(pessoas, frutaColecao) =>
new
{
NomeDono = pessoas.nome,
Frutas = frutaColecao.Select(s => s.nome)
});
foreach (var item in query)
{
Console.WriteLine($"Dono {item.NomeDono}, Frutas: {string.Join(",", item.Frutas)}");
}
// Dono Pedro, Frutas: Abacaxi,Maça
// Dono Jorge, Frutas:
// Dono Danilo, Frutas: Morango
```
## Join
```csharp=
Pessoa pedro = new Pessoa("Pedro");
Pessoa jorge = new Pessoa("Jorge");
Pessoa danilo = new Pessoa("Danilo");
Fruta abacaxi = new Fruta("Abacaxi", pedro);
Fruta maca = new Fruta("Maça", pedro);
Fruta banana = new Fruta("Banana", pedro);
Fruta morango = new Fruta("Morango", danilo);
List<Pessoa> pessoas = new List<Pessoa>() { pedro, jorge, danilo };
List<Fruta> frutas = new List<Fruta>() { abacaxi, maca, banana, morango };
var query = pessoas
.Join(frutas,
p => p,
f => f.dono,
(pessoas, fruta) =>
new
{
NomeDono = pessoas.nome,
Fruta = fruta.nome
});
foreach (var item in query)
{
Console.WriteLine($"Dono {item.NomeDono}, Frutas: {item.Fruta}");
// Dono Pedro, Frutas: Abacaxi
// Dono Pedro, Frutas: Maça
// Dono Pedro, Frutas: Banana
// Dono Danilo, Frutas: Morango
}
Console.ReadKey();
```
- Join preserva a ordem dos elementos de outer e para cada um desses elementos, a ordem dos elementos correspondentes de inner.
- Um GroupJoin é em SQL o que chamamos de “Left Outer JOIN”, enquanto um Join em SQL se refere a “Inner Join”. Resumindo, um GroupJoin fará um link entre 2 entidades, mesmo que o lado direito do link não tenha nada para vincular. Em contraste, o Join vinculará 2 entidades apenas se ambas as entidades contiverem um link entre elas.
## OrderBy, OrderByDescending
```csharp=
class Pet
{
public string Name { get; set; }
public int Age { get; set; }
}
public static void OrderByEx1()
{
Pet[] pets = { new Pet { Name="Barley", Age=8 },
new Pet { Name="Boots", Age=4 },
new Pet { Name="Whiskers", Age=1 } };
IEnumerable<Pet> query = pets.OrderBy(pet => pet.Age);
foreach (Pet pet in query)
{
Console.WriteLine("{0} - {1}", pet.Name, pet.Age);
}
}
/*
This code produces the following output:
Whiskers - 1
Boots - 4
Barley - 8
*/
```
## ThenBy, ThenByDescending
```csharp=
string[] fruits = { "grape", "passionfruit", "banana", "mango",
"orange", "raspberry", "apple", "blueberry" };
// Sort the strings first by their length and then
//alphabetically by passing the identity selector function.
IEnumerable<string> query =
fruits.OrderBy(fruit => fruit.Length).ThenBy(fruit => fruit);
foreach (string fruit in query)
{
Console.WriteLine(fruit);
}
/*
This code produces the following output:
apple
grape
mango
banana
orange
blueberry
raspberry
passionfruit
*/
```
- Esse método é implementado usando a execução adiada. 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 GetEnumerator** método diretamente ou usando o foreach no Visual C# ou For Each no Visual Basic.
## Reverse
- Ao contrário do OrderBy , esse método de classificação não considera os próprios valores reais para determinar a ordem. Em vez disso, ele apenas retorna os elementos na ordem inversa da qual eles são produzidos pela fonte subjacente.
```csharp=
char[] apple = { 'a', 'p', 'p', 'l', 'e' };
char[] reversed = apple.Reverse().ToArray();
foreach (char chr in reversed)
{
Console.Write(chr + " ");
}
Console.WriteLine();
/*
This code produces the following output:
e l p p a
*/
```
> https://docs.microsoft.com/pt-br/dotnet/api/system.linq.enumerable.groupjoin?view=net-5.0
> https://patrickdesjardins.com/blog/linq-groupjoin-and-join-differences
## Select
O operador Select sempre retorna uma coleção IEnumerable que contém elementos baseados em uma função de transformação.
```csharp=
namespace select
{
public class Produto
{
public string Nome;
public Produto(string nome)
{
Nome = nome;
}
}
class Program
{
static void Main(string[] args)
{
var produtos = new[]
{
new Produto("MORANGO"),
new Produto("LARANJA")
};
var resultado = produtos.Select(n => n.Nome.ToLower());
foreach(var nome in resultado)
{
Console.WriteLine(nome);
}
}
}
}
```
## SelectMany
O SelectMany no LINQ é usado para projetar cada elemento de uma sequência para um IEnumerable<T> e, em seguida, achatar as sequências resultantes em uma sequência. Isso significa que o operador SelectMany combina os registros de uma sequência de resultados e, em seguida, converte-o em um resultado.
```csharp=
static void Main(string[] args)
{
string[] frutas = { "Uva", "laranja", "banana" };
int[] numeros = { 1, 2, 3 };
var resultado = frutas.SelectMany(f => numeros, (f, a) => new
{
Fruta = f,
Numero = a
});
foreach (var o in resultado)
Console.WriteLine(o.Fruta + ", " + o.Numero);
}
resultado:
Uva, 1
Uva, 2
Uva, 3
laranja, 1
laranja, 2
laranja, 3
banana, 1
banana, 2
banana, 3
```
### Skip
Ele pula o número especificado de elementos em uma coleção
```csharp=
static void Main(string[] args)
{
string[] produtos = { "banana", "pera", "uva", "melancia", "maca", "limao" };
var resultado = produtos.Skip(4);
foreach (string produto in resultado)
Console.WriteLine(produto);
}
Resultado:
maca
limao
```
### SkipWhile
Ele retorna uma nova coleção que inclui todos os elementos restantes uma vez que a condição especificada se torna falsa para qualquer elemento.
```csharp=
static void Main(string[] args)
{
string[] numeros = { "one", "two", "three", "four", "five", "six" };
var resultado = numeros.SkipWhile(w => w.Length == 3);
foreach (string numero in resultado)
Console.WriteLine(numero);
}
Resultado:
Three
Four
Five
Six
```
### Take
O método de extensão Take() retorna o número especificado de elementos a partir do primeiro elemento.
```csharp=
IList<string> lista = new List<string>(){ "One", "Two", "Three", "Four", "Five" };
var novalista = lista.Take(2);
foreach(var str in novalista)
Console.WriteLine(str);
Resultado:
One
Two
```
### TakeWhile
O método de extensão TakeWhile() retorna os elementos da coleção dada até que a condição especificada seja verdadeira. Se o primeiro elemento em si não satisfaz a condição, então retorna uma coleção vazia.
```csharp=
IList<string> strList = new List<string>() { "Three", "Four", "Five", "Hundred" };
var result = strList.TakeWhile(s => s.Length > 4);
foreach(string str in result)
Console.WriteLine(str);
Resultado:
Three
```
## Quantifiers
### All
- Determina se todos os elementos de uma sequência atendem a uma condição.
- Retorna bool
```csharp=
List<int> lista = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
bool pares = lista.All(x => x % 2 == 0);
Console.WriteLine(pares);
// False
```
### Any
- Determina se qualquer elemento de uma sequência existe ou atende a uma condição
- Retorna bool
```csharp=
List<int> lista = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
bool temItens = lista.Any();
bool contemNum = lista.Any(x => x == 5);
Console.WriteLine(temItens);
Console.WriteLine(contemNum);
// True
// contemNum
```
### Contains
- Determina se uma sequência contém um elemento especificado.
- Retorna bool
- System.Linq
```csharp=
List<int> lista = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
bool contem = lista.Contains(3);
Console.WriteLine(contem);
// True
```
## Restriction
### Where
- Filtra uma sequência de valores com base num predicado.
- Retorna IEnumerable<TSource>
```csharp=
List<int> lista = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
List<int> filtro = lista.Where(x => x > 5).ToList();
foreach (int item in filtro)
{
Console.WriteLine(item);
}
// { 6, 7, 8, 9, 10 }
```
## Set
### Distinct
- Retorna os elementos distintos de uma sequência usando o comparador de igualdade padrão para comparar valores.
- Retorna IEnumerable<TSource>
```csharp=
List<int> lista = new List<int> { 1, 2, 3, 3, 5, 7, 4, 5, 6, 7 };
List<int> filtro = lista.Distinct().ToList();
foreach (int item in filtro)
{
Console.WriteLine(item);
}
// { 1, 2, 3, 5, 7, 4, 6}
```
### Except
- Produz a diferença de conjunto de duas sequências.
- Retorna IEnumerable<TSource>
```csharp=
List<int> lista = new List<int> { 1, 2, 3, 5, 7 };
List<int> lista2 = new List<int> { 1, 2};
List<int> filtro = lista.Except(lista2).ToList();
foreach (int item in filtro)
{
Console.WriteLine(item);
}
// { 3, 5, 7 }
```
### Intersect
- Produz a interseção de conjunto de duas sequências.
- Retorna IEnumerable<TSource>
```csharp=
List<int> lista = new List<int> { 1, 2, 3, 5, 7 };
List<int> lista2 = new List<int> { 1, 2 };
List<int> filtro = lista.Intersect(lista2).ToList();
foreach (int item in filtro)
{
Console.WriteLine(item);
}
// { 1, 2 }
```
### Union
- Produz a união de conjunto de duas sequências.
- Retorna IEnumerable<TSource>
```csharp=
List<int> lista = new List<int> { 1, 2, 3, 5, 7 };
List<int> lista2 = new List<int> { 1, 2};
List<int> filtro = lista.Union(lista2).ToList();
foreach (int item in filtro)
{
Console.WriteLine(item);
}
// { 1, 2, 3, 5, 7 }
```