
Após aprender como filtrar dados de coleções em C#, vamos continuar explorando os operadores funcionais de System.Linq. Agora vamos aprender como efetuar a projeção de coleções.
Os métodos Select e SelectMany possibilitam que uma determinada coleção seja projetada (transformada) em uma coleção diferente, através da aplicação de uma função em cada elemento desta. Em outras linguagens e plataformas, o equivalente ao Select é o map, e o equivalente ao SelectMany é o flatMap.
Transformando uma coleção em outra – Select
Considere a seguinte lista de números inteiros:
var numeros = new List<int>() { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
Vamos usar o método Select para aplicar uma função em cada elemento, e assim gerar uma coleção diferente:
// Multiplique cada elemento por 2.
var tabuadaDois = numeros.Select(n => n * 2).ToList();
// resultado: { 2, 4, 6, 8, 10, 12, 14, 16, 18, 20 }
// Eleve cada elemento ao quadrado.
var quadrado = numeros.Select(n => n * n).ToList();
// resultado: { 1, 4, 9, 16, 25, 36, 49, 64, 81, 100 }
// Transforme cada elemento em string.
var emString = numeros.Select(n => n.ToString()).ToList();
// resultado: { "1", "2", "3", "4", "5", "6", "7", "8", "9", "10" }
Existe uma sobrecarga do método Select que, além do elemento, recebe também o índice deste:
// Multiplique cada elemento por 2 e transforme em string,
// concatenando com o índice do elemento.
var lista = numeros.Select((n, i) => $"{i}: {n * 2}").ToList();
// resultado: { "0: 2", "1: 4", "2: 6", "3: 8", "4: 10", "5: 12", "6: 14", "7: 16", "8: 18", "9: 20" }
E agora, vamos brincar com objetos!
var funcionarios = new List<Funcionario>();
funcionarios.Add(new Funcionario(123, Cargo.Tecnico, "José Silva", "jose@empresa.com"));
funcionarios.Add(new Funcionario(124, Cargo.Auxiliar, "Arnaldo Antunes", "arnaldo@empresa.com"));
funcionarios.Add(new Funcionario(125, Cargo.Analista, "João Gilberto", "joao@empresa.com"));
funcionarios.Add(new Funcionario(126, Cargo.Especialista, "Marta Rocha", "marta@empresa.com"));
funcionarios.Add(new Funcionario(127, Cargo.Tecnico, "André Alves", "andre@empresa.com"));
funcionarios.Add(new Funcionario(128, Cargo.Especialista, "Gilberto Barros", "gilberto@empresa.com"));
funcionarios.Add(new Funcionario(129, Cargo.Gerente, "Alberto Roberto", "alberto@empresa.com"));
funcionarios.Add(new Funcionario(130, Cargo.Especialista, "Fernando Fernandes", "fernando@empresa.com"));
// Retornar apenas os e-mails dos funcionários com cargo técnico:
var emails = funcionarios.Where(f => f.Cargo = Cargo.Tecnico)
.Select(f => f.Email).ToList();
// resultado: { "jose@empresa.com", "andre@empresa.com" }
// Retornar uma string contendo matrícula, nome e e-mail dos funcionários:
var dados = funcionarios.Select(f => $"{f.Matricula} - {f.Nome} - {f.Email}").ToList();
// resultado: { "123 - José Silva - jose@empresa.com",
// "124 - Arnaldo Antunes - arnaldo@empresa.com",
// ...
// "130 - Fernando Fernandes - fernando@empresa.com" }
Transformando uma lista de listas em uma lista única – SelectMany
O método SelectMany vai além, ele pega uma lista de listas e transforma em uma lista. Por exemplo, considere as classes abaixo:
public class Diretorio
{
public string Nome { get; set; }
public List<string> Arquivos { get; set; }
}
// Dada uma lista de diretórios que contenha uma lista de arquivos,
// retorne uma lista com todos os arquivos de todos os diretórios:
var listaDir = new List<Diretorio>();
// preenchimento da lista omitido para facilitar
var todosArquivos = listaDir.SelectMany(d => d.Arquivos).ToList();
// resultado: lista de strings contendo todos os arquivos de todos os diretórios.
Como você pode ver os métodos Select e SelectMany são ferramentas poderosas para transformação de dados de uma coleção, poupando muitas linhas de código e, consequentemente, minimizando a ocorrência de bugs.