CodeGym /Cursos /C# SELF /Lista: List<T>

Lista: List<T>

C# SELF
Nivel 27, Lección 2
Disponible

1. Introducción

Imagina que llevas una lista de la compra. Hoy necesitas comprar 3 cosas, mañana — 10, y pasado mañana — solo una. Si usaras un array, tendrías que crear uno nuevo cada vez para la cantidad exacta de productos. O crear un array enorme "por si acaso", llevando un montón de huecos vacíos. Suena poco eficiente, ¿verdad?

Ahora imagina que tienes una mochila mágica que se expande sola cuando metes cosas y se encoge cuando las sacas. No necesitas saber de antemano cuántas cosas vas a meter. Simplemente las metes y la mochila se adapta. ¡Eso es justo lo que hace List<T> en el mundo de la programación en C#!

List<T> es una colección genérica que te permite guardar una secuencia de elementos de un tipo concreto. La palabra clave aquí es "dinámica". A diferencia de los arrays, List<T> puede cambiar su tamaño durante la ejecución del programa. Se encarga de su capacidad interna, aumentándola cuando hace falta.

¿Qué significa la letra T en List<T>? Es lo que se llama un parámetro de tipo. Cuando creas un List, indicas qué tipo de datos va a guardar en vez de T. Por ejemplo, List<int> solo guardará números enteros, List<string> — solo cadenas, y List<double> — solo números decimales. Así te aseguras de que no vas a meter una manzana en una lista de naranjas, lo cual es clave para la estabilidad y previsibilidad de tu código.

¿Para qué sirve esto?

En proyectos reales es muy común no saber de antemano cuántos elementos vas a tener. Por ejemplo:

  • Lista de usuarios que han entrado en la web.
  • Lista de productos en el carrito de una tienda online.
  • Lista de resultados de una búsqueda.
  • Lista de tareas en un planificador, que es justo lo que vamos a desarrollar ahora.

En todos estos casos la cantidad de elementos puede cambiar, y List<T> se convierte en nuestro mejor aliado.

Métodos principales de List<T>

Método Descripción Ejemplo
Add(T item)
Añadir un elemento al final de la lista
numbers.Add(5);
Insert(int idx, T)
Insertar en una posición concreta
numbers.Insert(0, 42);
Remove(T item)
Eliminar la primera aparición de un elemento
numbers.Remove(100);
RemoveAt(int idx)
Eliminar un elemento por índice
numbers.RemoveAt(2);
Clear()
Vaciar la lista
numbers.Clear();
Contains(T item)
Comprobar si la lista contiene un elemento
numbers.Contains(10);
IndexOf(T item)
Índice de la primera aparición
int pos = numbers.IndexOf(42);
Count
Cantidad de elementos en la lista
int n = numbers.Count;
Capacity
Capacidad del buffer interno
numbers.Capacity = 100;

2. Crear una lista (List<T>)

¡Vamos a la práctica! Imagina que queremos crear un gestor de tareas sencillo. Necesitamos una lista donde vamos a añadir nuestras tareas.

Para crear una nueva lista List<T> usamos el operador new, igual que al crear otros objetos.

Cómo declarar y crear un List

La sintaxis para crear una lista es muy parecida a la de los arrays, solo que en vez de corchetes usamos los signos < >:

using System.Collections.Generic;

List<int> numbers = new List<int>();

Comentarios para los que quieren detalles:
- List<int> es una lista de enteros (int). En vez de int puedes poner cualquier otro tipo: string, double, tu propia clase, etc.
- Al crearla, la lista está vacía — su longitud es 0.

Ejemplo: primer paso en nuestra app

Supón que tienes una app donde el usuario introducía nombre y edad (de las primeras lecciones). Ahora vamos a añadir la opción de guardar varios nombres en una lista para luego trabajar con ellos.

using System;
using System.Collections.Generic;

class Program
{
    static void Main()
    {
        List<string> names = new List<string>();

        Console.WriteLine("Introduce tres nombres:");
        for (int i = 0; i < 3; i++)
        {
            string name = Console.ReadLine();
            names.Add(name);
        }

        Console.WriteLine("Has introducido:");
        foreach (string n in names)
        {
            Console.WriteLine(n);
        }
    }
}

Fíjate en Add(). Es este método el que añade nuevos elementos a la lista. ¡Eso es lo que la hace dinámica!

¡Puedes crear una lista ya con elementos!

List<string> planets = new List<string> { "Mercurio", "Venus", "Tierra" };

Muy cómodo cuando ya sabes el "equipo inicial". Esta sintaxis se usa mucho en tests y para inicializar datos fijos.

3. Operaciones básicas con List<T>

Antes de pasar a los trucos y la magia, vamos a ver el "abecedario" de las listas.

Añadir elementos: Add()

Usar el método Add() es como poner una cosa nueva en la estantería:

List<int> numbers = new List<int>();
numbers.Add(42);
numbers.Add(100);

Ahora dentro: [42, 100]

Obtener la cantidad de elementos: Count

A diferencia de los arrays, en las listas la propiedad se llama Count, no Length:

int count = numbers.Count; // Devuelve 2

Recuerda: en listas se usa Count, en arrays y strings — Length. Son propiedades distintas para un propósito parecido.

Acceso a elementos por índice

Dos formas, ambas hacen lo mismo:

int first = numbers[0]; // 42
numbers[1] = 200; // Cambiamos 100 por 200

Importante: La indexación, igual que en los arrays, empieza en cero. ¡No intentes acceder a numbers[3] si solo tienes tres elementos!

Recorrer los elementos de la lista

Puedes usar un bucle for o foreach:

// Con for — si necesitas el índice
for (int i = 0; i < numbers.Count; i++)
{
    Console.WriteLine(numbers[i]);
}

// Con foreach — si no necesitas el índice
foreach (int number in numbers)
{
    Console.WriteLine(number);
}

foreach suele ser más fácil y claro, sobre todo con colecciones grandes.
Pero con él no puedes cambiar los elementos por índice ni salir antes del bucle con break, salvo que uses otras construcciones.

Insertar un elemento por índice: Insert()

El método Insert() sirve si quieres añadir un elemento no al final, sino donde quieras. Por ejemplo, en la segunda posición:

numbers.Insert(1, 55); // Inserta 55 en la posición con índice 1

Ahora numbers: [42, 55, 200]

Eliminar elementos

Eliminar de la lista es casi tan fácil como añadir:

numbers.Remove(55); // Elimina la PRIMERA aparición de 55
numbers.RemoveAt(0); // Elimina el elemento con índice 0
numbers.Clear(); // Vacía la lista completamente

Detalles sobre eliminar:
- Si intentas eliminar un valor que no existe con Remove, no pasa nada malo: la lista no cambia, no hay errores.
- Tras Clear() la lista vuelve a estar vacía.

4. Detalles útiles

Cómo crece List<T>

Cuando añades elementos a List<T>, no aumenta el tamaño de uno en uno. En vez de eso, List<T> reserva un bloque de memoria con margen (la capacidad interna — Capacity).

Cuando hay más elementos que la capacidad actual, la lista reserva un bloque de memoria más grande (normalmente el doble) y copia allí todos los valores antiguos:


Añadimos elementos → cabe → cabe → cabe →
Nuevo elemento no cabe → se crea un array más grande → se copian los datos → seguimos

Esto permite añadir elementos más rápido, porque la memoria solo se reorganiza de vez en cuando, no en cada Add.

var list = new List<int>();    // Capacity = 0
list.Add(1);                   // Capacity = 4
list.Add(2);                   // Capacity = 4
list.Add(3);                   // Capacity = 4
list.Add(4);                   // Capacity = 4
list.Add(5);                   // Capacity = 8 (¡expansión!)

Capacity vs. Count: ¿en qué se diferencian?

  • Count — cantidad de elementos añadidos a la lista.
  • Capacity — tamaño del array interno que guarda los elementos.
List<int> nums = new List<int>();
Console.WriteLine(nums.Count); // 0
Console.WriteLine(nums.Capacity); // Normalmente 0 o un tamaño pequeño

nums.Add(123);
Console.WriteLine(nums.Count); // 1
Console.WriteLine(nums.Capacity); // Ahora puede ser mayor que Count

nums.Capacity = 1000; // Puedes aumentar Capacity a mano si sabes que habrá muchos elementos

La mayoría de programadores solo usan Count, pero si haces apps donde el rendimiento es clave (por ejemplo, juegos o análisis de datos), ajustar Capacity puede ser útil.

5. Ejemplo

Seguimos mejorando nuestra pequeña app — ahora, por ejemplo, el usuario puede añadir sus números favoritos y luego trabajar con la lista: insertar, eliminar, mostrar y vaciar.

using System;
using System.Collections.Generic;

class Program
{
    static void Main()
    {
        List<int> favoriteNumbers = new List<int>();

        Console.WriteLine("Introduce tus números favoritos (uno por línea, 0 — terminar):");
        while (true)
        {
            int num = int.Parse(Console.ReadLine());
            if (num == 0) break;
            favoriteNumbers.Add(num);
        }

        Console.WriteLine("Tus números favoritos:");
        foreach (int n in favoriteNumbers)
        {
            Console.Write(n + " ");
        }

        Console.WriteLine("\n¿Quieres eliminar el primer número? (y/n)");
        if (Console.ReadLine().ToLower() == "y")
        {
            favoriteNumbers.RemoveAt(0);
        }

        Console.WriteLine("Ahora tu lista:");
        foreach (int n in favoriteNumbers)
        {
            Console.Write(n + " ");
        }
    }
}

Nota: Aquí usamos int.Parse. En proyectos reales es mejor comprobar siempre la entrada con int.TryParse para que el programa no "petee" con cualquier error del usuario.

6. Errores y "trampas" típicas de principiantes

Muy típico: escribes un bucle de 0 a List.Count, pero durante el bucle (por ejemplo, en un foreach) cambias la lista (añades o eliminas elementos). ¡No lo hagas! Los pros de la programación llaman a esto "modificar la colección durante la iteración". En la mayoría de los casos te saltará una excepción tipo InvalidOperationException.

Ejemplo de mal código:

foreach (int n in numbers)
{
    if (n < 0)
        numbers.Remove(n); // ¡BOOM! Runtime error.
}

Correcto: o bien primero guardas los índices/elementos a eliminar en otra lista, o usas un bucle for en sentido inverso.

2
Tarea
C# SELF, nivel 27, lección 2
Bloqueada
Trabajo con cadenas en List
Trabajo con cadenas en List
Comentarios
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION