TOC

This article has been localized into Spanish by the community.

Collections / Colecciones:

Lists / Listas

C# tiene un amplio rango de clases para lidear con listas. Implementando la interfaz de iList y la implementación mas popular es la lista generica, normalmente referida como List<T> La "T" especifica el tipo de objeto contenido en la lista, el cual tiene el beneficio añadido de que el compliador verificará y se asegurará que se agreguen unicamente objetos del tipo de la lista - en otras palabras la lista tipo -List <Type> es segura para agregar elementos de un mismo tipo.

List es muy parecida a la clase ArrayList, que era la opción de ir a la lista antes de que C # admitiera listas genéricas. Por lo tanto, también verá que List puede hacer muchas de las mismas cosas que una Matriz (que por cierto también implementa la interfaz IList), pero en muchas situaciones, List es más simple y fácil de trabajar. Por ejemplo, no tiene que crear una Lista con un tamaño específico; en su lugar, puede crearla y .NET la expandirá automáticamente para ajustarse a la cantidad de elementos a medida que los agregue.

Como mencioné, la T se refiere a tipo y se usa para especificar el tipo de objetos que quieres que contenga la lista. En nuestro primer ejemplo, te mostraré como crear una lista que debería contener strings:

List<string> listOfStrings = new List<string>();

Esto crea una lista vacía, pero agregarle algo luego es muy fácil con el método Add:

listOfStrings.Add("a string");

Sin embargo, si intenta agregar algo que no sea una cadena, el compilador se quejará de inmediato:

listOfStrings.Add(2);
Error   CS1503  Argument 1: cannot convert from 'int' to 'string'

Inicializando una lista con ítems

En el ejemplo anterior, acabamos de crear una lista y luego le agregamos un elemento. Sin embargo, C # realmente le permite crear una lista Y agregarle elementos dentro de la misma declaración, utilizando una técnica llamada inicializadores de colección. Veamos cómo se hace:

List<string> listOfNames = new List<string>()
{
    "John Doe",
    "Jane Doe",
    "Joe Doe"
};

La sintaxis es bastante simple: antes del punto y coma final habitual, tenemos un conjunto de llaves, que a su vez contiene una lista de los valores que queremos que estén presentes en la lista desde el principio. Como se trata de una lista de strings, los objetos iniciales que proporcionamos deben ser del tipo de string. Sin embargo, se puede lograr exactamente lo mismo para la lista de otros tipos, incluso si estamos usando nuestras propias clases, como demostraré en el siguiente ejemplo.

Trabajando con los elementos.

Hay varias formas de trabajar con los elementos de una lista genérica y mostrar algunos de ellos. He creado un ejemplo más amplio:

using System;
using System.Collections.Generic;

namespace Lists
{
    class Program
    {
static void Main(string[] args)
{
    List<User> listOfUsers = new List<User>()
    {
new User() { Name = "John Doe", Age = 42 },
new User() { Name = "Jane Doe", Age = 34 },
new User() { Name = "Joe Doe", Age = 8 },
    };

    for(int i = 0; i < listOfUsers.Count; i++)
    {
Console.WriteLine(listOfUsers[i].Name + " is " + listOfUsers[i].Age + " years old");
    }
    Console.ReadKey();
}
    }

    class User
    {
public string Name { get; set; }

public int Age { get; set; }
    }
}

Comencemos desde abajo, donde definimos una clase simple para almacenar información sobre un Usuario, solo un nombre y una edad. Volvemos a la parte superior del ejemplo, donde he cambiado nuestra lista para usar esta clase de usuario en lugar de cadenas simples. Utilizo un inicializador de colección para completar la lista con los usuarios: observe cómo la sintaxis es la misma que antes, solo que es un poco más compleja porque se trata de un objeto más complejo que una cadena.

Una vez que tenemos lista la lista, utilizo un bucle for para ejecutarla; para saber cuántas iteraciones vamos a hacer, uso la propiedad Countde la lista. En cada iteración, accedo al usuario en cuestión a través del indexador de la lista, utilizando la sintaxis de corchetes (por ejemplo, listOfUsers [i]). Una vez que tengo el usuario, escribo el nombre y la edad.

Añadiendo, insertando y borrando elementos.

Ya intentamos agregar un solo elemento a una lista, pero hay más opciones para hacerlo. En primer lugar, puede insertar un elemento en lugar de agregarlo; la diferencia es que, si bien el método Addsiempre agrega al final de la lista, el método Insertle permite insertar un elemento en una posición específica. Aquí hay un ejemplo:

List<string> listOfNames = new List<string>()
{
    "Joe Doe"
};
// Insert at the top (index 0)
listOfNames.Insert(0, "John Doe");
// Insert in the middle (index 1)
listOfNames.Insert(1, "Jane Doe");

Comenzamos la lista con solo un elemento, pero luego insertamos dos elementos más, primero en la parte superior de la lista y luego en el medio. El primer parámetro del método Insert es el índice donde queremos insertar el elemento. Sin embargo, tenga cuidado: se lanzará una excepción si intenta insertar un elemento en el índice 3, ¡si la lista tiene menos elementos!

Añadiendo múltiples elementos.

Al igual que tenemos los métodos Agregar e Insertar para agregar un solo elemento, también hay métodos correspondientes para agregar e insertar múltiples elementos. Se llaman AddRange()() e InsertRange() () y acepta cualquier tipo de colección que implemente la interfaz IEnumerable como parámetro; esto podría ser, p.e. una matriz de elementos u otra lista, qué elementos desea agregar o insertar en la lista actual.

Como ejemplo de los métodos Range, hagamos algo divertido: combinamos el método AddRange con un inicializador de colección para agregar varios nombres nuevos a una lista existente en una sola declaración:

listOfNames.AddRange(new string[]
    {
"Jenna Doe",
"Another Doe"
    });

Simplemente creamos una serie de cadenas sobre la marcha e inmediatamente agregamos sus elementos a nuestra lista de nombres del ejemplo anterior.

Borrando elementos.

Actualmente hay tres métodos a su disposición cuando desea eliminar uno o varios elementos de una lista: Remove(), RemoveAt() y RemoveAll().

El método Remove() toma solo un parámetro: el elemento que desea eliminar. Esto es genial para, p.e. una lista de cadenas o enteros, porque simplemente puede escribir el elemento que desea eliminar. Por otro lado, si tienes una lista de objetos complejos, primero deberías encontrar ese objeto, para tener una referencia que puedas pasar al método Remove (). "Vamos a tratar eso más tarde. Aquí hay un ejemplo muy básico sobre cómo puedes eliminar un solo elemento con el método Remove ():

List<string> listOfNames = new List<string>()
{
    "John Doe",
    "Jane Doe",
    "Joe Doe",
    "Another Doe"
};

listOfNames.Remove("Joe Doe");

El método Remove () simplemente recorre la lista en iteración hasta que encuentra la primera instancia del objeto que especificó para su eliminación, y ellos la eliminan; solo elimina una instancia, y si especifica un elemento en la lista que no existe, No se arroja ningún error. El método devuelve truesi pudo eliminar un elemento y false si no lo fue.

El método RemoveAt() aprovecha el hecho de que la lista genérica se basa en índices al permitirle eliminar un elemento en función de su índice / posición en la lista. Por ejemplo, podría eliminar el primer elemento de la lista así:

listOfNames.RemoveAt(0);

O el último elemento de la lista así:

listOfNames.RemoveAt(listOfNames.Count - 1);

Nuevamente, esto solo elimina un solo elemento y esta vez, debe tener cuidado al proporcionar el índice del elemento que se eliminará; si utiliza un índice que está fuera de los límites (inferior a 0 o superior a la cantidad de elementos) se lanzará una excepción! Entonces, a menos que esté seguro de lo que está haciendo, es posible que desee envolver el método RemoveAt () en un bloque try-catch para manejar la excepción (explicado en detalle en otra parte de este tutorial). El método RemoveAt () no devuelve nada, por lo que tendrá que verificar la cantidad de elementos en la lista antes y después de la llamada, para decidir si fue exitosa, por otro lado, si sabe que tiene un índice que existe en la lista, de la que siempre debe asegurarse, siempre puede esperar que RemoveAt () sea exitoso.

RemoveAll() es el más complejo de los métodos remove, pero definitivamente también el más poderoso. Toma un delegado a un método como parámetro y este método decide si un elemento debe eliminarse o no devolviendo verdadero o falso. Esto le permite aplicar su propia lógica al eliminar elementos y también le permite eliminar más de un elemento a la vez. Los delegados serán tratados en otra parte de este tutorial, porque es un tema grande y complejo, pero todavía quiero que entiendan lo genial que es el método RemoveAll, así que aquí hay un ejemplo:

List<string> listOfNames = new List<string>()
{
    "John Doe",
    "Jane Doe",
    "Joe Doe",
    "Another Doe"
};

listOfNames.RemoveAll(name =>
{
    if (name.StartsWith("J"))
return true;
    else
return false;
});

En este ejemplo, utilizamos un método anónimo (nuevamente demasiado complejo para ser explicado aquí, pero será tratado en otro capítulo) como un parámetro para el método RemoveAll. Nuestro método anónimo es bastante simple: se llamará para cada elemento de la lista y tendrá un parámetro llamado name, que es, por supuesto, el elemento actual en la iteración. Mira este nombre y si comienza con "J", se devuelve true; de lo contrario, es false. El método RemoveAll () usa esta respuesta (verdadero o falso) para decidir si cada elemento debe eliminarse o no. Al final, esto deja nuestra lista inicial con solo un miembro de Doe: Another Doe.

Ordenando elementos de Lista

Hasta ahora, los elementos de la lista con los que hemos trabajado se han utilizado en el orden en que se agregaron a la lista. Sin embargo, es posible que desee ordenar los elementos de una manera específica, p. alfabéticamente en el caso de nuestra lista de nombres. La List<T> tiene un método Sort () que podemos usar para esto:

List<string> listOfNames = new List<string>()
{
    "John Doe",
    "Jane Doe",
    "Joe Doe",
    "Another Doe"
};
listOfNames.Sort();
foreach (string name in listOfNames)
    Console.WriteLine(name);

Como verá en la salida, los elementos de la lista ahora se han ordenado alfabéticamente, y si lo desea en orden descendente (de Z a A), simplemente llame al método Reverse()después de realizar la clasificación:

listOfNames.Sort();
listOfNames.Reverse();

Entonces ordenar una lista fue bastante fácil, ¿verdad? Bueno, fue muy fácil porque tenemos una lista de cadenas y .NET Framework sabe exactamente cómo comparar dos cadenas. Si tiene una lista de números, .NET, por supuesto, también sabrá cómo ordenar eso. Por otro lado, es posible que tenga una lista de objetos personalizados (ya que laList<T>puede contener cualquier objeto) que .NET no tiene la posibilidad de saber cómo comparar. Hay varias soluciones a este problema, p. implementando la interfaz IComparable o usando LINQ (lo veremos más adelante en este tutorial), pero como solución rápida, también podemos proporcionar un método para que llame el método Sort (), para aprender cómo se comparan dos elementos uno contra el otro, así:

using System;
using System.Collections.Generic;

namespace ListSort
{
    class Program
    {
static void Main(string[] args)
{
    List<User> listOfUsers = new List<User>()
    {
new User() { Name = "John Doe", Age = 42 },
new User() { Name = "Jane Doe", Age = 39 },
new User() { Name = "Joe Doe", Age = 13 },
    };
    listOfUsers.Sort(CompareUsers);
    foreach (User user in listOfUsers)
Console.WriteLine(user.Name + ": " + user.Age + " years old");
}

public static int CompareUsers(User user1, User user2)
{
    return user1.Age.CompareTo(user2.Age);
}
    }

    public class User
    {
public string Name { get; set; }
public int Age { get; set; }
    }
}

Esto agregó bastante código a nuestro ejemplo, pero en realidad no es demasiado complicado. Si comenzamos desde abajo, he creado una clase de usuario muy simple, que consta de un nombre y una edad. En el medio, he declarado un método llamado CompareUsers(): toma dos usuarios como parámetros y luego devuelve un número entero, que indicará si un elemento es "más pequeño", "igual" o "más grande" (-1, 0 o 1). El método Sort () utilizará estos valores para mover los elementos de modo que el orden de los elementos coincida con lo que queremos. En este caso, simplemente uso la propiedad Age para comparar, esencialmente dejándonos con una lista de usuarios ordenados por su edad.

Resumen

Este artículo es uno de los más largos en este tutorial, pero espero que haya aprendido mucho sobre las listas, porque mientras más programación haga, más se dará cuenta de lo importantes que son las listas y los diccionarios. Hablando de diccionarios, los discutiremos en el próximo artículo.

This article has been fully translated into the following languages: Is your preferred language not on the list? Click here to help us translate this article into your language!