HOWTO · Csharp

Convertir lista en diccionario en C#

Aprende a convertir una lista de C# en un diccionario con LINQ o un bucle foreach, y a elegir cómo gestionar las claves duplicadas.

En esta página

Usa LINQ ToDictionary() cuando quieras que cada elemento de origen se convierta en una entrada del diccionario, o recurre a un bucle foreach si prefieres crear las entradas explícitamente. En ambos casos, elige una clave única; si puede repetirse, agrupa los elementos o decide qué valor conservar antes de crear el diccionario.

Convertir una lista en un diccionario en C#

Un diccionario almacena valores asociados a claves, así que para convertir una lista hay que decidir qué propiedad proporcionará cada clave y qué valor se asociará a ella. Por ejemplo, una lista de temporadas puede usar el Id de cada temporada como clave y conservar el objeto Season completo como valor. Los tipos de clave y de valor del Dictionary<TKey, TValue> resultante dependen de esas decisiones. Los ejemplos completos definen una clase Season sencilla cuando hace falta.

Usar LINQ ToDictionary() para convertir una lista en un diccionario

Importa System.Linq para usar LINQ. ToDictionary() recibe un selector de claves y, de forma opcional, un selector de elementos. El primer selector elige la clave; el segundo determina el valor almacenado. Si omites el selector de elementos, el valor será el elemento de origen completo.

Ejecuta este ejemplo:

El código y las etiquetas o salidas visibles de esta sección se mantienen en inglés.

using System.Collections.Generic;
using System.Linq;

class Season
{
    public int Id { get; set; }
    public string Name { get; set; } = "";
}

class Program
{
    static void Main()
    {
        var seasons = new List<Season>
        {
            new Season { Id = 1, Name = "Spring" },
            new Season { Id = 2, Name = "Summer" }
        };

        Dictionary<int, Season> seasonsById = seasons.ToDictionary(s => s.Id);
        Dictionary<int, string> namesById = seasons.ToDictionary(s => s.Id, s => s.Name);
        System.GC.KeepAlive(seasonsById);
        System.GC.KeepAlive(namesById);
    }
}

Usa s => s.Id para las claves y s => s.Name para los valores cuando solo necesites los nombres. Con la sobrecarga que recibe un solo selector, seasonsById almacena cada objeto Season completo. Para que la conversión funcione, las claves deben ser únicas.

Convertir una lista en un diccionario con un bucle foreach

Un bucle hace explícita la correspondencia y permite añadir lógica para cada elemento. Este ejemplo crea la misma asociación de identificadores con temporadas que el ejemplo de LINQ:

El código y las etiquetas o salidas visibles de esta sección se mantienen en inglés.

using System.Collections.Generic;

class Season
{
    public int Id { get; set; }
    public string Name { get; set; } = "";
}

class Program
{
    static void Main()
    {
        var seasons = new List<Season>
        {
            new Season { Id = 1, Name = "Spring" },
            new Season { Id = 2, Name = "Summer" }
        };
        var seasonsById = new Dictionary<int, Season>();

        foreach (var season in seasons)
        {
            seasonsById.Add(season.Id, season);
        }
    }
}

Add usa season.Id como clave y el objeto season como valor. Elige cualquiera de los dos métodos según cuál resulte más claro y según el trabajo que necesites realizar al crear el diccionario; el rendimiento depende de la carga de trabajo, así que un bucle no es categóricamente más rápido.

Comprender y gestionar las claves duplicadas

Un diccionario solo puede contener un valor para cada clave. ToDictionary() lanza ArgumentException si la clave seleccionada aparece más de una vez, y Dictionary.Add(key, value) también lanza ArgumentException cuando esa clave ya existe. Ninguna de las dos operaciones reemplaza el valor existente de forma silenciosa.

Si en los datos de origen puede haber claves repetidas, decide qué debe representar el valor del diccionario para cada una: un recuento, una colección con todos los elementos coincidentes o un elemento elegido. Si primero agrupas los elementos, cada clave distinta tendrá un solo grupo, que después podrás convertir sin duplicar claves.

Contar las claves duplicadas

Agrupa los elementos por el valor repetido y usa Count() de cada grupo como valor del diccionario. Este ejemplo cuenta todas las apariciones de cada cadena, incluida la primera; por eso, un recuento superior a uno indica que la clave está repetida.

El código y las etiquetas o salidas visibles de esta sección se mantienen en inglés.

using System.Collections.Generic;
using System.Linq;

class Program
{
    static void Main()
    {
        var words = new List<string> { "You", "Breaking Bad", "Marvel", "You" };
        var countsByWord = words.GroupBy(word => word)
            .ToDictionary(group => group.Key, group => group.Count());

        foreach (var entry in countsByWord)
        {
            System.Console.WriteLine($"{entry.Key}={entry.Value}");
        }
    }
}
You=2
Breaking Bad=1
Marvel=1

En esta ejecución, el orden de iteración del diccionario puede variar. La salida es:

Breaking Bad=1
Marvel=1
You=2

El resultado es un Dictionary<string, int>: cada palabra distinta es una clave y su valor indica cuántas veces apareció. Si la aplicación solo necesita contar las apariciones adicionales después de la primera, resta uno a cada recuento al interpretar el resultado.

Conservar todos los valores de cada clave

Para conservar todos los elementos asociados a una clave, agrúpalos por esa clave y convierte cada grupo en una lista. Así, el diccionario asocia cada año con todas las temporadas estrenadas ese año.

El código y las etiquetas o salidas visibles de esta sección se mantienen en inglés.

using System.Collections.Generic;
using System.Linq;

class Season
{
    public int YearOfRelease { get; set; }
    public string Name { get; set; } = "";
}

class Program
{
    static void Main()
    {
        var seasons = new List<Season>
        {
            new Season { YearOfRelease = 2020, Name = "North" },
            new Season { YearOfRelease = 2020, Name = "South" },
            new Season { YearOfRelease = 2021, Name = "West" }
        };
        Dictionary<int, List<Season>> seasonsByYear = seasons
            .GroupBy(season => season.YearOfRelease)
            .ToDictionary(group => group.Key, group => group.ToList());

        foreach (var entry in seasonsByYear)
        {
            System.Console.WriteLine(
                $"{entry.Key}={string.Join(", ", entry.Value.ConvertAll(season => season.Name))}");
        }
    }
}

Cada clave aparece una sola vez en el diccionario, mientras que su lista contiene todos los elementos de origen del grupo. Usa esta estructura cuando el código posterior necesite consultar o procesar cada elemento, en lugar de reducir el grupo a un único valor.

Conservar un valor por cada clave

Si basta con un elemento representativo, selecciona uno de cada grupo. First() elige el primer elemento de la secuencia del grupo, por lo que el resultado depende del orden de origen. Si el elemento representativo debe cumplir un criterio específico, aplica otra regla de selección, como ordenar por una propiedad antes de llamar a First().

El código y las etiquetas o salidas visibles de esta sección se mantienen en inglés.

using System.Collections.Generic;
using System.Linq;

class Season
{
    public int YearOfRelease { get; set; }
    public string Name { get; set; } = "";
}

class Program
{
    static void Main()
    {
        var seasons = new List<Season>
        {
            new Season { YearOfRelease = 2020, Name = "North" },
            new Season { YearOfRelease = 2020, Name = "South" },
            new Season { YearOfRelease = 2021, Name = "West" }
        };
        Dictionary<int, Season> firstSeasonByYear = seasons
            .GroupBy(season => season.YearOfRelease)
            .ToDictionary(group => group.Key, group => group.First());
        System.GC.KeepAlive(firstSeasonByYear);
    }
}

La agrupación garantiza que haya una entrada del diccionario por año; First() proporciona el valor de esa entrada. Si el orden de la secuencia de origen no tiene significado para la aplicación, define explícitamente el orden deseado antes de seleccionar un elemento representativo.

Gestionar claves duplicadas con un bucle

Para agrupar elementos con un bucle, guarda una lista para cada clave. Crea la lista solo la primera vez que aparezca la clave y, después, añade cada elemento. Así evitas llamar dos veces a Add para la misma clave y conservas todos los valores.

El código y las etiquetas o salidas visibles de esta sección se mantienen en inglés.

using System.Collections.Generic;

class Season
{
    public int YearOfRelease { get; set; }
    public string Name { get; set; } = "";
}

class Program
{
    static void Main()
    {
        var seasons = new List<Season>
        {
            new Season { YearOfRelease = 2020, Name = "North" },
            new Season { YearOfRelease = 2020, Name = "South" },
            new Season { YearOfRelease = 2021, Name = "West" }
        };
        var seasonsByYear = new Dictionary<int, List<Season>>();

        foreach (var season in seasons)
        {
            if (!seasonsByYear.ContainsKey(season.YearOfRelease))
            {
                seasonsByYear.Add(season.YearOfRelease, new List<Season>());
            }
            seasonsByYear[season.YearOfRelease].Add(season);
        }
    }
}

El diccionario resultante tiene una lista por año y añade cada temporada a la lista correspondiente. Si solo necesitas un valor o un recuento, actualiza ese valor dentro del bucle en lugar de almacenar una lista.