1. Introdução
Vamos ser sinceros, arrays são massa, mas têm suas limitações. Precisa mudar o tamanho? Vai ter que criar um array novo e copiar tudo na mão! Precisa achar um elemento rapidinho por uma chave? O array vai te dizer: "Então, tenta aí você mesmo".
A vida real tá cheia de situações onde array não resolve. Imagina que você tá fazendo um app pra controlar livros numa biblioteca (salve, nosso mini-sistema de estudos!). No começo você tem 5 livros — beleza, array dá conta. Uma semana depois já são 500, aí alguém devolve um livro, outro some com um... É aí que entram as coleções!
Coleções são tipo uns containers que sabem:
- Mudar de tamanho sozinhas.
- Fazer busca, adicionar e remover rapidinho.
- Dar jeitos mais práticos de mexer nos dados: ordenar, filtrar, processar em grupo.
No .NET tem algumas "famílias" principais de coleções. Hoje a gente vai ver as mais usadas: listas (List<T>), dicionários (Dictionary<TKey, TValue>), conjuntos (HashSet<T>), filas, pilhas e também as interfaces que estão por trás delas.
2. Tipos principais de coleções
Mesmo sem entrar ainda nos tipos genéricos de coleções, é importante sacar quais são as categorias principais de coleções e pra que cada uma serve. Pensa como se fossem tipos diferentes de "caixas", cada uma com suas manhas:
Listas (Lists)
O que é? Uma sequência ordenada de elementos. Tipo uma lista de compras ou lista de alunos na chamada.
Principais características: Os elementos têm ordem (dá pra acessar pelo índice, igual array). Pode ter elementos repetidos. O tamanho é dinâmico.
Quando usar? Quando a ordem dos elementos importa e você quer poder adicionar/remover do final da lista rapidinho, ou pegar um elemento pela posição.
Exemplo do dia a dia: Fila do caixa, lista de participantes de um webinar, sequência de frames numa animação.
Dicionários/Mapeamentos (Dictionaries/Maps)
O que é? Um conjunto de pares "chave-valor". Tipo um dicionário de verdade, onde cada palavra (chave) tem um significado (valor).
Principais características: Cada chave é única. A chave serve pra buscar o valor rapidinho. A ordem dos elementos normalmente não é garantida.
Quando usar? Quando você precisa achar um valor por algum identificador único (a chave).
Exemplo do dia a dia: Agenda de contatos (nome - telefone), banco de dados de produtos (ID do produto - descrição), configurações do app (nome da config - valor).
Conjuntos (Sets)
O que é? Um grupo sem ordem de elementos únicos. Igual conjunto na matemática.
Principais características: Não pode ter elementos repetidos. A ordem não importa. É otimizado pra checar se um elemento existe e pra fazer operações de conjunto (união, interseção).
Quando usar? Quando você quer guardar só valores únicos e checar rapidinho se algo tá no grupo.
Exemplo do dia a dia: Lista de visitantes únicos do site, conjunto de tags de um artigo, lista de palavras pra autocompletar (sem repetição).
Filas (Queues)
O que é? Coleção que funciona no esquema "primeiro que entra, primeiro que sai" (FIFO - First-In, First-Out).
Principais características: Elementos entram no final da fila e saem do começo.
Quando usar? Pra simular processos onde a ordem de chegada importa, tipo sistema de tickets de suporte, fila de impressão.
Pilhas (Stacks)
O que é? Coleção que funciona no esquema "último que entra, primeiro que sai" (LIFO - Last-In, First-Out).
Principais características: Elementos entram e saem sempre do mesmo lado (do topo da pilha).
Quando usar? Pra controlar histórico de ações (desfazer no editor), processar estruturas aninhadas, recursão.
Diferenças entre os tipos de coleções
| Tipo de coleção | Analogia | Princípio principal | Acesso por índice? | Ordem dos elementos? | Permite duplicados? | Operações principais |
|---|---|---|---|---|---|---|
| Array | Fila de caixas numeradas | Tamanho fixo | Sim | Sim | Sim | Pegar/definir pelo índice |
| Lista | Lista de compras | Dinâmico, ordenado | Sim | Sim | Sim | Adicionar, remover, buscar |
| Dicionário | Dicionário (chave-valor) | Chaves únicas | Não | Não (normalmente) | Não (por chave) | Pegar por chave, adicionar |
| Conjunto | Grupo de objetos únicos | Só elementos únicos | Não | Não | Não | Checar existência, união |
| Fila | Fila do caixa | FIFO (Primeiro entra - primeiro sai) | Não | Sim | Sim | Adicionar no final, tirar do começo |
| Pilha | Pilha de pratos | LIFO (Último entra - primeiro sai) | Não | Sim | Sim | Adicionar no topo, tirar do topo |
3. Lista: List<T>
Lista é a coleção mais usada em C#. Mais até que array. Lista é tipo um array, mas cresce sozinha. Dá pra adicionar e remover elementos sem dor de cabeça.
using System;
using System.Collections.Generic;
var numbers = new List<int>(); // Criando uma lista vazia de inteiros
numbers.Add(10); // Adicionando elemento
numbers.Add(15);
numbers.Add(42);
Console.WriteLine(numbers[0]); // 10
numbers.Remove(15); // Removendo elemento pelo valor
foreach (var number in numbers)
{
Console.WriteLine(number);
}
// Vai mostrar: 10 e 42
Por que List<T> é melhor que array pra guardar dados quando você não sabe o tamanho antes?
— Porque não precisa reservar mais memória nem copiar array na mão quando adiciona elementos — a coleção faz tudo pra você!
Quando usar List<T>?
- Lista dinâmica, quando precisa adicionar, remover, mudar elementos.
- Não precisa buscar rápido por chave (isso é com dicionário).
- Usa muito pra trabalhar com conjuntos ordenados.
4. Dicionário Dictionary<TKey, TValue>
Array (e lista) deixa você guardar uma lista de valores em cada posição, e cada posição tem um índice. Mas o dicionário é uma coleção que deixa você usar uma string (nome) no lugar do número (índice). Esse nome da posição é chamado de chave.
Se você precisa achar rapidinho um valor por uma chave (tipo, pelo número da carteirinha — o nome do leitor), aí é dicionário na veia.
using System.Collections.Generic;
var phoneBook = new Dictionary<string, string>();
phoneBook["Anya"] = "+79992221133";
phoneBook["Maksim"] = "+79998887766";
Console.WriteLine(phoneBook["Anya"]); // +79992221133
// Dá pra checar se a chave existe:
if (phoneBook.ContainsKey("Vasya"))
{
Console.WriteLine(phoneBook["Vasya"]);
}
else
{
Console.WriteLine("Não tem esse número!");
}
Curiosidade: Dicionários também são chamados de "arrays associativos". Eles são feitos usando hash table, o que faz a busca pela chave ser super rápida (quase instantânea, tirando colisão — mas isso é papo pra depois).
Principais características
- Chave é única: não pode ter duas iguais no dicionário.
- Valores podem repetir.
- Busca, adiciona e remove por chave rapidão.
5. Conjunto: HashSet<T>
Além de listas e dicionários, conjuntos (sets) também são bem populares. É quase uma lista, só que mais simples: lista sem ordem fixa dos elementos. O conjunto só guarda os valores, pra quando a ordem não importa.
Por exemplo, se você só quer saber se algo tá no grupo, sem duplicados, e não liga pra ordem — usa conjunto.
using System.Collections.Generic;
var knownUsers = new HashSet<string>();
knownUsers.Add("admin");
knownUsers.Add("guest");
knownUsers.Add("admin"); // Se tentar adicionar de novo — ignora
Console.WriteLine(knownUsers.Contains("admin")); // True
Console.WriteLine(knownUsers.Count); // 2
Conjunto checa rapidinho se um elemento existe.
Pra que serve conjunto?
— Tipo, se você quer guardar todos os usuários únicos que abriram o app no mês, ou uma lista de autores únicos de livros.
Características
- Só guarda elementos únicos (se tentar repetir, ignora).
- Não tem índice igual lista.
- Checagem rápida de existência.
6. Filas e pilhas
Tem também estruturas pra casos especiais: fila e pilha. Na real, é tipo lista, só que com regras pra adicionar e tirar elementos.
Queue<T>: fila (first in — first out)
Às vezes você precisa de uma "fila" — novo elemento entra no final, e pra tirar, só do começo.
using System.Collections.Generic;
var queue = new Queue<string>();
queue.Enqueue("Primeiro");
queue.Enqueue("Segundo");
queue.Enqueue("Terceiro");
Console.WriteLine(queue.Dequeue()); // "Primeiro"
Console.WriteLine(queue.Peek()); // "Segundo", mas não tira
Stack<T>: pilha (first in — last out)
Pilha é o contrário: o último que entrou é o primeiro a sair. Serve pra parser, chamada de funções e até pra desfazer ação em editor.
using System.Collections.Generic;
var stack = new Stack<string>();
stack.Push("Um");
stack.Push("Dois");
stack.Push("Três");
Console.WriteLine(stack.Pop()); // "Três"
Console.WriteLine(stack.Peek()); // "Dois"
7. Tabela: comparando as coleções principais
| Coleção | Elementos únicos | Acesso por índice | Busca rápida por chave | Inserção/remoção |
|---|---|---|---|---|
|
Não | Sim | Não | Rápido no final |
|
Chaves | Não | Sim | Rápido por chave |
|
Sim | Não | Sim* | Rápido por valor |
|
Não | Não | Não | Rápido (FIFO) |
|
Não | Não | Não | Rápido (LIFO) |
A gente vai ver cada coleção dessas em detalhes nas próximas aulas. E vamos começar com o mistério da letra <T>...
GO TO FULL VERSION