List<T> é uma coleção ordenada que cresce e diminui conforme você adiciona e remove itens. Ela fica em System.Collections.Generic, é indexada como um array (list[0]) e é a escolha padrão para "um monte de coisas" em C#.
Criando uma lista e adicionando itens
O parâmetro de tipo entre os sinais de menor e maior diz o que a lista guarda: List<string>, List<int>, List<Order>.
Saída:
2
Zoe, Ana, Ben, Chloe, Dev
Ana
Ana B.
3
Count é uma propriedade, não um método (arrays usam Length, o LINQ tem um método Count(); em uma lista, use a propriedade). Insert empurra cada item seguinte uma posição, então inserir no começo de uma lista grande custa um tempo proporcional ao tamanho dela. Add no fim é a operação barata.
Removendo itens
Há quatro formas de remover, dependendo do que você sabe sobre o item:
Saída:
True: 85, 62, 40, 91, 55
False
62, 40, 91, 55
2 removed: 62, 91
Caught ArgumentOutOfRangeException
0
Remove recebe um valor e apaga só a primeira correspondência. Para apagar todas as cópias de um valor, use RemoveAll(s => s == 40). Um índice inválido em uma lista lança ArgumentOutOfRangeException (um array lança IndexOutOfRangeException no lugar), tanto em list[i] quanto em RemoveAt(i). RemoveRange(index, count) remove um bloco.
Count vs Capacity
Uma lista guarda os itens em um array interno. Capacity é o tamanho desse array; Count é quantas posições estão em uso. Quando Count chega a Capacity, o próximo Add aloca um array com o dobro do tamanho e copia tudo para ele.
Saída:
Count 0, Capacity 0
Count 1, Capacity 4
Count 2, Capacity 4
Count 3, Capacity 4
Count 4, Capacity 4
Count 5, Capacity 8
Count 6, Capacity 8
Count 7, Capacity 8
Count 8, Capacity 8
Count 9, Capacity 16
Count 0, Capacity 1000
Dobrar o tamanho faz com que a maioria das chamadas a Add seja só uma escrita em uma posição livre. Se você sabe mais ou menos quantos itens vêm por aí, passe o número ao construtor para evitar as cópias intermediárias. Repare que new List<int>(1000) ainda tem Count 0: list[0] nela lança exceção. Capacidade é espaço, não itens.
Buscando: Contains, IndexOf, Find, Exists
Saída:
True
2
-1
32.00
2 cheap items
False
2
True
False
Find retorna a primeira correspondência ou o valor padrão do tipo (null para uma classe) quando nada corresponde, então verifique antes de usar o resultado. A última linha imprime False porque Contains usa Equals, e uma classe sem sobrescrever Equals compara referências: um Product novo com os mesmos campos é outro objeto. Busque por uma propriedade com Exists ou Find, ou sobrescreva Equals e GetHashCode na classe.
Todos esses métodos percorrem a lista desde o começo, então cada chamada é O(n). Para consultas repetidas por uma chave, um Dictionary responde em tempo constante.
Ordenando uma lista
Sort() ordena a própria lista usando a ordem natural dos itens. Passe uma lambda de comparação para ordenar por qualquer outra coisa.
Saída:
1, 2, 5, 9
9, 5, 2, 1
Ben 95, Ana 120, Chloe 150
Chloe 150, Ben 95, Ana 120
Ben 95, Ana 120, Chloe 150
Uma comparação retorna um número negativo quando a deve vir primeiro, positivo quando b deve, e zero quando empatam; CompareTo produz exatamente isso. Duas diferenças entre Sort e o OrderBy do LINQ importam na prática:
Sortmuda a lista;OrderByretorna uma nova sequência e deixa a lista como está.Sortnão é estável: itens considerados iguais podem trocar de lugar.OrderByé estável, eThenByadiciona uma segunda chave:players.OrderBy(p => p.Score).ThenBy(p => p.Name).
Chamar Sort() em uma lista da sua própria classe sem uma comparação lança InvalidOperationException, porque a lista não sabe como ordenar os itens. Passe uma comparação ou implemente IComparable<T> na classe.
Reverse() inverte a própria lista. Como System.Linq também define uma extensão Reverse, list.Reverse() em uma List<T> escolhe a versão que altera a lista, que não retorna nada.
Percorrendo, e removendo durante a iteração
foreach lê cada item em ordem. Um laço for também dá o índice. O que você não pode fazer é adicionar ou remover itens no meio de um foreach sobre a mesma lista:
Saída:
Caught InvalidOperationException
120, 80, 60
120, 80, 60
A exceção é InvalidOperationException com a mensagem "Collection was modified; enumeration operation may not execute." Um laço for para frente não lança exceção, mas pula sem aviso o item logo depois de cada um que você remove, porque tudo desce um índice. Percorrer de trás para frente evita isso. Uma terceira solução é iterar sobre uma cópia: foreach (var t in orders.ToList()).
Mudar uma propriedade de um item dentro do foreach (por exemplo order.Status = "sent") não tem problema. Adicionar ou remover itens quebra o enumerador, e substituir um pelo indexador (orders[i] = 0) também.
Convertendo entre listas e arrays
Saída:
4
3
4, 4, 4, 4
Oslo / Lima / Pune / Kyiv
As duas direções copiam os elementos para um armazenamento novo, então mudar a lista depois não afeta o array. ConvertAll é a versão da própria lista para o Select(...).ToList() do LINQ. Imprimir uma lista com Console.WriteLine(list) mostra o nome do tipo (System.Collections.Generic.List`1[System.String]); use string.Join.
Referência rápida
| Tarefa | Código |
|---|---|
| Criar | var l = new List<int>(); ou new List<int> { 1, 2 } |
| Adicionar no fim | l.Add(x), l.AddRange(items) |
| Inserir em uma posição | l.Insert(i, x) |
| Remover a primeira correspondência | l.Remove(x) (retorna bool) |
| Remover por índice | l.RemoveAt(i) |
| Remover por condição | l.RemoveAll(x => ...) (retorna a quantidade) |
| Número de itens | l.Count |
| Contém | l.Contains(x), l.Exists(x => ...) |
| Buscar | l.Find(...), l.FindAll(...), l.FindIndex(...) |
| Ordenar a própria lista | l.Sort(), l.Sort((a, b) => ...) |
| Cópia ordenada | l.OrderBy(x => ...).ToList() |
| Para array | l.ToArray() |
Erros comuns
- Remover dentro de um
foreach. LançaInvalidOperationException; useRemoveAllou um laçoforde trás para frente. - Esperar que
Remove(x)remova todas as cópias. Ele remove a primeira; useRemoveAll. - Usar
Containsem objetos semEquals. Ele compara referências; busque por propriedade comExists. - Acessar por índice uma lista criada com capacidade.
new List<int>(10)está vazia; adicione itens antes. - Supor que
Sortmantém a ordem dos empates. Não mantém; useOrderByquando a ordem entre iguais importar. - Atribuir uma lista para compartilhá-la e se surpreender com as mudanças.
var copy = list;é a mesma lista;new List<T>(list)é uma cópia.
Perguntas frequentes
Como adicionar itens a uma List em C#?
list.Add(item) acrescenta um item no fim, list.AddRange(otherCollection) acrescenta vários e list.Insert(index, item) coloca um item em uma posição e empurra o resto. Você também pode preencher a lista ao criá-la: var names = new List<string> { "Ana", "Ben" };.
Como remover um item de uma List em C#?
Remove(value) remove o primeiro item correspondente e retorna true se encontrou um. RemoveAt(index) remove pela posição. RemoveAll(x => condition) remove todos os itens que correspondem e retorna quantos removeu. Clear() esvazia a lista.
Como verificar se uma List contém um valor em C#?
list.Contains(value) retorna true ou false. Ele compara com Equals, então para suas próprias classes compara referências, a menos que a classe sobrescreva Equals. Para verificar por uma propriedade, use list.Exists(p => p.Name == "Ana") ou o list.Any(...) do LINQ.
Como ordenar uma List por uma propriedade em C#?
Passe uma comparação para Sort: people.Sort((a, b) => a.Age.CompareTo(b.Age)) ordena a própria lista. Troque a e b para ordem decrescente. Ou use LINQ, que retorna uma nova sequência ordenada e mantém itens iguais na ordem original: people.OrderBy(p => p.Age).ToList().
Por que recebo "Collection was modified; enumeration operation may not execute"?
Você adicionou, removeu ou substituiu (list[i] = x) itens enquanto um foreach percorria a mesma lista, e o enumerador lança InvalidOperationException no passo seguinte. Use list.RemoveAll(condition), percorra de trás para frente com um laço for, ou itere sobre uma cópia como list.ToList().
Qual a diferença entre Count e Capacity?
Count é o número de itens na lista. Capacity é o tamanho do array interno, que é pelo menos Count. Quando o array enche, a lista aloca um novo com o dobro do tamanho e copia os itens, então o Add é rápido na média.