Colecciones y LINQ en C#
Las colecciones en C# representan uno de los pilares fundamentales para el manejo eficiente de datos en aplicaciones modernas. A diferencia de los arrays tradicionales, las colecciones ofrecen flexibilidad dinámica y funcionalidades avanzadas que permiten almacenar, organizar y manipular conjuntos de elementos de manera más sofisticada.
Fundamentos de las colecciones
El namespace System.Collections.Generic proporciona las estructuras de datos más utilizadas en el desarrollo profesional. Estas colecciones están tipadas, lo que significa que garantizan la seguridad de tipos en tiempo de compilación y ofrecen mejor rendimiento que sus contrapartes no genéricas.
Las colecciones genéricas más importantes incluyen List
// Declaración de diferentes tipos de colecciones
List<string> nombres = new List<string>();
Dictionary<int, string> usuarios = new Dictionary<int, string>();
HashSet<int> numerosUnicos = new HashSet<int>();
Manipulación básica de colecciones
La interfaz ICollection
List<int> numeros = new List<int> { 1, 2, 3, 4, 5 };
// Operaciones básicas
numeros.Add(6); // Agregar elemento
numeros.Remove(3); // Eliminar elemento específico
bool existe = numeros.Contains(4); // Verificar existencia
int cantidad = numeros.Count; // Obtener tamaño
Las operaciones de búsqueda en colecciones varían según el tipo utilizado. Mientras que List
Introducción a LINQ
Language Integrated Query (LINQ) revoluciona la forma de trabajar con colecciones al proporcionar una sintaxis declarativa para consultar y transformar datos. LINQ permite escribir consultas similares a SQL directamente en código C#, haciendo que las operaciones complejas sobre colecciones sean más legibles y mantenibles.
List<int> numeros = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
// Consulta LINQ para obtener números pares
var numerosPares = from n in numeros
where n % 2 == 0
select n;
La sintaxis de métodos de LINQ utiliza métodos de extensión que se encadenan para crear consultas fluidas. Esta aproximación es especialmente útil cuando necesitas realizar transformaciones complejas o cuando trabajas con expresiones lambda.
// Misma consulta usando sintaxis de métodos
var numerosPares = numeros.Where(n => n % 2 == 0);
// Consulta más compleja con múltiples operaciones
var resultado = numeros
.Where(n => n > 3)
.Select(n => n * 2)
.OrderByDescending(n => n)
.Take(3);
Operadores LINQ fundamentales
Los operadores de filtrado como Where() permiten seleccionar elementos que cumplan condiciones específicas. Estos operadores utilizan predicados (funciones que devuelven bool) para determinar qué elementos incluir en el resultado.
Los operadores de proyección como Select() transforman cada elemento de la colección original en un nuevo formato. Esto es especialmente útil cuando necesitas extraer propiedades específicas o realizar cálculos sobre los datos.
List<string> palabras = new List<string> { "casa", "perro", "gato", "elefante" };
// Filtrar palabras con más de 4 caracteres y convertir a mayúsculas
var palabrasLargas = palabras
.Where(p => p.Length > 4)
.Select(p => p.ToUpper());
Los operadores de agregación como Sum(), Count(), Average() y Max() calculan valores únicos a partir de toda la colección. Estos operadores son fundamentales para generar estadísticas y resúmenes de datos.
List<int> calificaciones = new List<int> { 85, 92, 78, 96, 88 };
double promedio = calificaciones.Average();
int maxima = calificaciones.Max();
int aprobados = calificaciones.Count(c => c >= 80);
Consultas complejas y agrupamiento
El operador GroupBy() organiza elementos en grupos basados en una clave común. Esta funcionalidad es esencial cuando necesitas categorizar datos o realizar análisis por grupos.
List<string> palabras = new List<string> { "casa", "coche", "perro", "gato", "camión" };
// Agrupar palabras por su primera letra
var gruposPorLetra = palabras
.GroupBy(p => p[0])
.Select(g => new { Letra = g.Key, Palabras = g.ToList() });
Las consultas anidadas permiten trabajar con estructuras de datos más complejas, combinando múltiples colecciones o realizando operaciones sobre los resultados de otras consultas.
La evaluación diferida (lazy evaluation) es una característica clave de LINQ que significa que las consultas no se ejecutan hasta que realmente necesitas los resultados. Esto optimiza el rendimiento al evitar procesamiento innecesario.
var consulta = numeros.Where(n => n > 5); // No se ejecuta aquí
// La consulta se ejecuta cuando iteras sobre los resultados
foreach (int numero in consulta)
{
Console.WriteLine(numero);
}
Lecciones de este módulo
Explora todas las lecciones disponibles en Colecciones y LINQ
Explora más sobre CSharp
Descubre más recursos de CSharp

Alan Sastre
Ingeniero de Software y formador, CEO en CertiDevs
Ingeniero de software especializado en Full Stack y en Inteligencia Artificial. Como CEO de CertiDevs, CSharp es una de sus áreas de expertise. Con más de 15 años programando, 6K seguidores en LinkedIn y experiencia como formador, Alan se dedica a crear contenido educativo de calidad para desarrolladores de todos los niveles.