1. Introducción
Si alguna vez has tenido un cajón lleno de calcetines y has intentado encontrar un par, ya te has topado con el problema de la ordenación. Cuando todo está desordenado, buscar lo que necesitas se convierte en una misión imposible. En programación con colecciones — lo mismo.
Ordenar es el proceso de poner los elementos de una colección en cierto orden (por ejemplo, alfabético, por valor, fecha, etc.). Esto es importante para:
- Mostrar datos al usuario (a nadie le gusta el caos).
- Facilitar la búsqueda (por ejemplo, la búsqueda binaria solo funciona en colecciones ordenadas).
- Comparaciones, informes, exportaciones y otras operaciones.
Pregunta del millón: "¿Y si solo tengo cinco elementos, puedo no ordenar?" — Teóricamente sí, pero en cuanto cinco se convierten en quinientos o cinco mil, sin automatización no hay manera.
En .NET hay dos enfoques principales para ordenar:
- Cambiar la colección original (por ejemplo, ordenar List<T> con el método Sort).
- Crear una copia ordenada de la colección (por ejemplo, clonar un array y luego ordenar).
Ordenar listas con el método .Sort()
El método Sort() está en la clase List<T>, porque esta clase implementa la interfaz IList<T>, dando acceso por índice y permitiendo cambiar el orden de los elementos.
Ejemplo — ordenar números de menor a mayor:
using System;
using System.Collections.Generic;
class Program
{
static void Main()
{
var numbers = new List<int> { 5, 2, 9, 1, 5, 6 };
numbers.Sort();
Console.WriteLine("Ordenación de menor a mayor:");
foreach(var number in numbers)
{
Console.Write($"{number} "); // 1 2 5 5 6 9
}
}
}
Aquí la ordenación es "in place": la lista original numbers cambia, los elementos se reordenan.
Ordenar cadenas
Ordenar también funciona genial para strings:
var words = new List<string> { "naranja", "manzana", "plátano", "pera" };
words.Sort();
Console.WriteLine(string.Join(", ", words)); // manzana, naranja, pera, plátano
Dato curioso: por defecto, la ordenación de strings va por orden Unicode, no por el "alfabeto humano" (sobre todo con varios idiomas, tenlo en cuenta en apps multilingües).
2. Ordenar con reglas propias
A veces la ordenación "por defecto" no vale. Por ejemplo, quieres ordenar usuarios no por nombre, sino por edad o fecha de registro.
Ordenar con expresión lambda (método Sort(Comparison<T>))
Puedes llamar al método Sort pasando una regla especial de ordenación — una función que compara dos elementos.
Ordenar usuarios por edad:
class User
{
public string Name { get; set; }
public int Age { get; set; }
}
// ...
var users = new List<User>
{
new User { Name = "Alicia", Age = 30 },
new User { Name = "Bob", Age = 25 },
new User { Name = "Eva", Age = 35 }
};
users.Sort((u1, u2) => u1.Age.CompareTo(u2.Age));
foreach (var user in users)
{
Console.WriteLine($"{user.Name}: {user.Age}");
}
// Salida:
// Bob: 25
// Alicia: 30
// Eva: 35
¿Cómo funciona esta magia? La lambda (u1, u2) => u1.Age.CompareTo(u2.Age) devuelve un número negativo si u1 es más joven, positivo si es mayor, y 0 si tienen la misma edad.
Usar la interfaz IComparer<T>
A veces mola sacar la regla de ordenación a una clase aparte, por ejemplo si tienes muchas colecciones y lógica compleja.
class UserAgeComparer : IComparer<User>
{
public int Compare(User x, User y)
{
return x.Age.CompareTo(y.Age);
}
}
// ...
var users = new List<User>{ /* ... */ };
users.Sort(new UserAgeComparer()); // ahora ordena por edad
Esto es útil si necesitas la ordenación en varias partes del programa o tienes muchas formas de ordenar.
Ordenar por varios campos a mano
Si algunos usuarios tienen la misma edad, pero quieres ordenarlos por nombre dentro del mismo grupo de edad:
users.Sort((u1, u2) => {
int ageCompare = u1.Age.CompareTo(u2.Age);
if (ageCompare != 0)
return ageCompare;
else
return u1.Name.CompareTo(u2.Name);
});
Ahora primero ordena por edad, luego por nombre.
3. Ordenar una copia de la colección (sin tocar la original)
Si no quieres cambiar la lista original, cópiala antes de ordenar:
var copy = new List<int>(numbers);
copy.Sort();
Para objetos personalizados — igual:
var usersCopy = new List<User>(users);
usersCopy.Sort((a, b) => a.Age.CompareTo(b.Age));
4. Ordenar arrays
Con arrays (T[]) también es bastante fácil:
int[] numbers = { 4, 2, 9, 7 };
Array.Sort(numbers); // el array original cambia
Para ordenación "custom":
Array.Sort(numbers, (a, b) => b.CompareTo(a)); // orden descendente
Ojo, Array.Sort cambia el array original, no devuelve uno nuevo. Si quieres guardar el original, copia el array antes:
int[] oldNumbers = { 3, 2, 1 };
int[] copy = (int[])oldNumbers.Clone();
Array.Sort(copy);
5. "Ordenar" diccionarios (Dictionary<TKey, TValue>)
Dictionary<TKey, TValue> — es una colección desordenada por naturaleza (o sea, no garantiza el orden al enumerar). Pero a veces quieres "pares ordenados".
Para obtener claves o valores ordenados, crea una lista, copia los pares y ordénalos como quieras:
var dict = new Dictionary<string, int>
{
{ "manzana", 2 },
{ "naranja", 5 },
{ "pera", 3 }
};
// Ordenar por clave:
var keyValueList = new List<KeyValuePair<string, int>>(dict);
keyValueList.Sort((a, b) => a.Key.CompareTo(b.Key));
foreach (var kv in keyValueList)
{
Console.WriteLine($"{kv.Key}: {kv.Value}");
}
// Ordenar por valor:
keyValueList.Sort((a, b) => a.Value.CompareTo(b.Value));
foreach (var kv in keyValueList)
{
Console.WriteLine($"{kv.Key}: {kv.Value}");
}
Si quieres una lista ordenada de claves o valores:
var sortedKeys = new List<string>(dict.Keys);
sortedKeys.Sort();
var sortedValues = new List<int>(dict.Values);
sortedValues.Sort();
Pero ojo, la estructura Dictionary no cambia — solo obtienes una enumeración ordenada. En .NET 9 aparecerá OrderedDictionary<TKey, TValue>, que mantiene el orden de los elementos. No es común, pero a veces hace falta.
6. Trucos útiles
¿Es obligatorio implementar la interfaz de comparación?
Fácil: si quieres que tus objetos "sepan" cómo compararse (por ejemplo, por fecha o nombre), implementa la interfaz IComparable<T>.
class Product : IComparable<Product>
{
public string Name { get; set; }
public decimal Price { get; set; }
public int CompareTo(Product other)
{
return Price.CompareTo(other.Price);
}
}
Ahora puedes hacer:
var products = new List<Product> { /* ... */ };
products.Sort(); // ordena por precio
Si la comparación por defecto no te mola — usa IComparer<T> o pasa una lambda, como arriba.
Ordenar lista de usuarios alfabéticamente
Por ejemplo, en la app tienes una lista de usuarios:
List<string> users = new List<string> { "Víctor", "Ana", "Catalina", "Boris" };
users.Sort(); // ahora users está ordenado: Ana, Boris, Catalina, Víctor
Repartir tareas por urgencia
class Task
{
public string Title { get; set; }
public int Priority { get; set; } // 1 - urgente, 2 - importante, 3 - se puede posponer
}
var todo = new List<Task>
{
new Task { Title = "Hacer los deberes", Priority = 2 },
new Task { Title = "Comprar pan", Priority = 1 },
new Task { Title = "Ver una serie", Priority = 3 }
};
todo.Sort((a, b) => a.Priority.CompareTo(b.Priority));
foreach (var task in todo)
Console.WriteLine($"{task.Priority}: {task.Title}");
Comparación de formas de ordenar
| Colección | ¿Cambia in place? | Método para ordenar | ¿Se puede poner regla? |
|---|---|---|---|
|
Sí | |
Sí: lambda o IComparer |
|
Sí | |
Sí: lambda o IComparer |
|
No | — (creamos lista y ordenamos) | Sí: con lambda o IComparer |
7. Errores típicos y matices de la ordenación
Ordenar in place — ¡cambia la colección original! Si los datos originales no deben cambiar — cópialos antes.
Intentar ordenar una colección inmutable (por ejemplo, ReadOnlyCollection<T>) dará error en tiempo de ejecución.
Comparar strings puede variar según la cultura: la ordenación de strings (sobre todo con cirílico, diéresis, etc.) puede ser distinta en diferentes locales. Para ordenar bien usa Comparer.Create(...) con la cultura que toque.
Ordenar diccionarios no cambia su estructura — siempre obtienes una nueva secuencia de pares (o una lista nueva).
Para ordenaciones complejas usa la interfaz IComparer<T> con tu lógica.
Aquí tienes un ejemplo de ordenación incorrecta (típico error de novato):
var numbers = new List<int> { 1, 2, 3 };
var sorted = numbers.Sort(); // ERROR: ¡Sort() devuelve void!
Correcto:
numbers.Sort(); // cambia numbers in place
// Si quieres una colección nueva:
var sorted = new List<int>(numbers);
sorted.Sort();
GO TO FULL VERSION