1. Introdução
Se tu já teve uma gaveta cheia de meias e tentou achar um par, já passou pelo problema de ordenação. Quando tá tudo bagunçado, achar o que tu quer vira uma missão. Em programação com coleções, é a mesma coisa.
Ordenação é o processo de organizar os elementos de uma coleção por algum critério (tipo ordem alfabética, valor, data, etc). Isso é importante pra:
- Mostrar dados pro usuário (ninguém curte bagunça).
- Facilitar buscas (tipo, busca binária só rola em coleções ordenadas).
- Comparações, relatórios, exportação e outras paradas.
Pergunta de um milhão: "E se eu só tenho cinco elementos, preciso ordenar?" — Teoricamente, não, mas quando cinco viram quinhentos ou cinco mil, sem automatizar não dá.
No .NET tem dois jeitos principais de ordenar:
- Mudar a coleção original (tipo, ordenar List<T> usando o método Sort).
- Criar uma cópia ordenada da coleção (tipo, clonar um array e ordenar depois).
Ordenando listas com o método .Sort()
O método Sort() existe na classe List<T>, porque essa classe implementa a interface IList<T>, dando acesso por índice e permitindo mudar a ordem dos elementos.
Exemplo — ordenando números em ordem crescente:
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("Ordenação crescente:");
foreach(var number in numbers)
{
Console.Write($"{number} "); // 1 2 5 5 6 9
}
}
}
Aqui a ordenação é "in place": a lista original numbers muda, os elementos trocam de lugar nela.
Ordenando strings
Ordenação funciona de boa pra strings também:
var words = new List<string> { "laranja", "maçã", "banana", "pêra" };
words.Sort();
Console.WriteLine(string.Join(", ", words)); // banana, laranja, maçã, pêra
Curiosidade: por padrão, a ordenação de string segue a ordem Unicode, não a ordem "humana" do alfabeto (principalmente pra idiomas diferentes, fica ligado nisso em apps multilíngues).
2. Ordenação por regras próprias
Às vezes a ordenação padrão não serve. Tipo, tu quer ordenar usuários não pelo nome, mas pela idade ou data de cadastro.
Ordenando com lambda expression (método Sort(Comparison<T>))
O método Sort pode ser chamado passando uma regra especial de ordenação — uma função que compara dois elementos.
Ordenando usuários por idade:
class User
{
public string Name { get; set; }
public int Age { get; set; }
}
// ...
var users = new List<User>
{
new User { Name = "Alice", 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}");
}
// Saída:
// Bob: 25
// Alice: 30
// Eva: 35
Como funciona essa mágica? A lambda (u1, u2) => u1.Age.CompareTo(u2.Age) retorna um número negativo se u1 for mais novo, positivo se for mais velho, e 0 se as idades forem iguais.
Usando a interface IComparer<T>
Às vezes tu quer jogar a regra de ordenação pra uma classe separada, tipo se tu tem várias coleções e lógica mais complexa.
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()); // agora ordena por idade
Isso é útil se tu precisa ordenar em vários lugares do código ou tem várias ordenações diferentes.
Ordenando por vários campos na mão
Se alguns usuários têm a mesma idade, mas tu quer ordenar pelo nome dentro do mesmo grupo de idade:
users.Sort((u1, u2) => {
int ageCompare = u1.Age.CompareTo(u2.Age);
if (ageCompare != 0)
return ageCompare;
else
return u1.Name.CompareTo(u2.Name);
});
Agora ordena primeiro por idade, depois por nome.
3. Ordenando uma cópia da coleção (sem mudar a original)
Se tu não quer mexer na lista original, copia ela antes de ordenar:
var copy = new List<int>(numbers);
copy.Sort();
Pra objetos customizados — mesma ideia:
var usersCopy = new List<User>(users);
usersCopy.Sort((a, b) => a.Age.CompareTo(b.Age));
4. Ordenando arrays
Com arrays (T[]) também é bem simples:
int[] numbers = { 4, 2, 9, 7 };
Array.Sort(numbers); // muda o array original
Pra ordenação "custom":
Array.Sort(numbers, (a, b) => b.CompareTo(a)); // ordena decrescente
Repara que Array.Sort muda o array original, não retorna um novo. Se tu quer manter o original, copia antes:
int[] oldNumbers = { 3, 2, 1 };
int[] copy = (int[])oldNumbers.Clone();
Array.Sort(copy);
5. "Ordenando" dicionários (Dictionary<TKey, TValue>)
Dictionary<TKey, TValue> é uma coleção não ordenada por padrão (ou seja, não garante ordem ao percorrer). Mas às vezes tu quer pegar "pares ordenados".
Pra pegar chaves ou valores ordenados, cria uma lista, copia os pares pra lá e ordena do jeito que quiser:
var dict = new Dictionary<string, int>
{
{ "maçã", 2 },
{ "laranja", 5 },
{ "pêra", 3 }
};
// Ordenando por chave:
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}");
}
// Ordenando por valor:
keyValueList.Sort((a, b) => a.Value.CompareTo(b.Value));
foreach (var kv in keyValueList)
{
Console.WriteLine($"{kv.Key}: {kv.Value}");
}
Se tu quiser só uma lista ordenada de chaves ou valores:
var sortedKeys = new List<string>(dict.Keys);
sortedKeys.Sort();
var sortedValues = new List<int>(dict.Values);
sortedValues.Sort();
Mas lembra, a estrutura do Dictionary não muda — tu só pega uma enumeração ordenada. No .NET 9 vai ter o OrderedDictionary<TKey, TValue>, que mantém a ordem dos elementos. Não é sempre, mas às vezes tu vai precisar disso.
6. Dicas úteis
Precisa implementar interface de comparação?
É simples: se tu quer que teus objetos "saibam" como se comparar (tipo por data ou nome), implementa a interface 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);
}
}
Agora tu pode fazer:
var products = new List<Product> { /* ... */ };
products.Sort(); // ordena por preço
Se a comparação padrão não serve — usa IComparer<T> ou passa uma lambda, como mostrei antes.
Ordenando lista de usuários em ordem alfabética
Digamos que no app tem uma lista de usuários:
List<string> users = new List<string> { "Victor", "Anna", "Ekaterina", "Boris" };
users.Sort(); // agora users tá ordenado: Anna, Boris, Ekaterina, Victor
Distribuindo tarefas por prioridade
class Task
{
public string Title { get; set; }
public int Priority { get; set; } // 1 - urgente, 2 - importante, 3 - pode deixar pra depois
}
var todo = new List<Task>
{
new Task { Title = "Fazer dever de casa", Priority = 2 },
new Task { Title = "Comprar pão", Priority = 1 },
new Task { Title = "Assistir série", Priority = 3 }
};
todo.Sort((a, b) => a.Priority.CompareTo(b.Priority));
foreach (var task in todo)
Console.WriteLine($"{task.Priority}: {task.Title}");
Comparando jeitos de ordenar
| Coleção | Muda na hora? | Método pra ordenar | Dá pra passar regra? |
|---|---|---|---|
|
Sim | |
Sim: lambda ou IComparer |
|
Sim | |
Sim: lambda ou IComparer |
|
Não | — (cria lista e ordena) | Sim: via lambda ou IComparer |
7. Erros comuns e detalhes de ordenação
Ordenação in place — muda a coleção original! Se tu não pode mexer nos dados originais — copia antes.
Tentar ordenar coleção imutável (tipo ReadOnlyCollection<T>) vai dar erro em tempo de execução.
Comparação de strings muda em culturas diferentes: ordenar strings (principalmente com acentos, cirílico, etc.) pode dar resultado diferente em cada localidade. Pra ordenar certo usa Comparer.Create(...) com a cultura certa.
Ordenar dicionário não muda a estrutura dele — sempre retorna uma nova sequência de pares (ou nova lista).
Pra ordem complexa usa interface IComparer<T> com tua lógica.
Exemplo de ordenação errada (pra tu não cair nessa):
var numbers = new List<int> { 1, 2, 3 };
var sorted = numbers.Sort(); // ERRO: Sort() retorna void!
O certo:
numbers.Sort(); // muda numbers na hora
// Se tu quer uma nova coleção:
var sorted = new List<int>(numbers);
sorted.Sort();
GO TO FULL VERSION