Menu

List em C#: Add, Remove, Contains, Find e Sort

List<T> é o array que cresce do C#. Veja como criar uma lista, adicionar e inserir itens, remover por valor, índice ou condição, buscar com Contains e Find, ordenar por uma propriedade e evitar o erro de modificar uma lista dentro de um foreach.

Esta página tem editores executáveis - edite, execute e veja a saída na hora.

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:

  • Sort muda a lista; OrderBy retorna uma nova sequência e deixa a lista como está.
  • Sort não é estável: itens considerados iguais podem trocar de lugar. OrderBy é estável, e ThenBy adiciona 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

TarefaCódigo
Criarvar l = new List<int>(); ou new List<int> { 1, 2 }
Adicionar no fiml.Add(x), l.AddRange(items)
Inserir em uma posiçãol.Insert(i, x)
Remover a primeira correspondêncial.Remove(x) (retorna bool)
Remover por índicel.RemoveAt(i)
Remover por condiçãol.RemoveAll(x => ...) (retorna a quantidade)
Número de itensl.Count
Contéml.Contains(x), l.Exists(x => ...)
Buscarl.Find(...), l.FindAll(...), l.FindIndex(...)
Ordenar a própria listal.Sort(), l.Sort((a, b) => ...)
Cópia ordenadal.OrderBy(x => ...).ToList()
Para arrayl.ToArray()

Erros comuns

  • Remover dentro de um foreach. Lança InvalidOperationException; use RemoveAll ou um laço for de trás para frente.
  • Esperar que Remove(x) remova todas as cópias. Ele remove a primeira; use RemoveAll.
  • Usar Contains em objetos sem Equals. Ele compara referências; busque por propriedade com Exists.
  • Acessar por índice uma lista criada com capacidade. new List<int>(10) está vazia; adicione itens antes.
  • Supor que Sort mantém a ordem dos empates. Não mantém; use OrderBy quando 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.

Coddy programming languages illustration

Aprenda a programar com o Coddy

COMEÇAR