Array versus List : Quando usar qual?

MyClass[] array; List list; 

Quais são os cenários em que um é preferível ao outro? E porque?

É raro, na realidade, que você queira usar um array. Definitivamente, use uma List sempre que quiser adicionar / remover dados, já que o redimensionamento de matrizes é caro. Se você sabe que os dados têm tamanho fixo e você deseja micro-otimizar por alguma razão muito específica (após o benchmarking), então um array pode ser útil.

List oferece muito mais funcionalidade do que um array (embora o LINQ o valorize um pouco) e é quase sempre a escolha certa. Exceto pelos argumentos params , é claro. ;-p

Como um contador – List é unidimensional; onde-como você tem matrizes retangulares (etc) como int[,] ou string[,,] – mas existem outras maneiras de modelar tais dados (se você precisar) em um modelo de object.

Veja também:

  • Como / quando abandonar o uso de matrizes em c # .net?
  • Matrizes, qual é o objective?

Dito isso, faço muito uso de matrizes no meu projeto de protobufnet ; inteiramente por desempenho:

  • Ele faz um monte de mudança de bits, então um byte[] é essencial para a codificação;
  • Eu uso um buffer local byte[] que preencho antes de enviar para o stream subjacente (e vv); mais rápido que BufferedStream etc;
  • ele usa internamente um modelo de objects baseado em array ( Foo[] ao invés de List ), já que o tamanho é fixo uma vez construído e precisa ser muito rápido.

Mas isso é definitivamente uma exceção; para processamento geral de linha de negócios, uma List ganha todas as vezes.

Realmente apenas respondendo para adicionar um link que eu estou surpreso não foi mencionado ainda: input do blog de Eric’s Lippert em “Arrays considerado um pouco prejudicial”.

Você pode julgar pelo título que está sugerindo usar collections sempre que possível – mas, como Marc corretamente aponta, há muitos lugares onde um array é realmente a única solução prática.

Use uma matriz quando você está lidando com dados que são:

  • fixo em tamanho, ou improvável que cresça muito
  • adequadamente grande (mais de 10, 50, 100 elementos, dependendo do algoritmo)
  • você estará fazendo muita indexação, ou seja, você sabe que muitas vezes você vai querer o terceiro elemento, ou o quinto, ou o que for.

Use uma lista para:

  • listas de dados de tamanho variável
  • que são usados ​​principalmente como uma pilha ou uma fila ou precisam ser iterados em sua totalidade
  • quando você não quer escrever uma expressão para derivar o tamanho final da matriz para a declaração e você não quer escolher um número grande

Use um hashmap para:

  • listas de dados de tamanho variável
  • que precisam ser indexados como um array

Na realidade, você desejará uma lista ou um hashmap quase todo o tempo. Da próxima vez que você escolher uma estrutura de dados, pense no que ela deve fazer bem para você (ou seu código, de qualquer forma). Então escolha algo baseado nisso. Em caso de dúvida, escolha algo tão geral quanto possível, ou seja, uma interface que você pode replace facilmente a implementação. Alguns bons links nas outras respostas também.

Não obstante as outras respostas recomendando List , você desejará usar arrays ao manipular:

  • dados de bitmap de imagem
  • outras estruturas de dados de baixo nível (isto é, protocolos de rede)

A menos que você esteja realmente preocupado com o desempenho, e com isso quero dizer: “Por que você está usando .Net em vez de C ++?” você deve ficar com List <>. É mais fácil manter e faz todo o trabalho sujo de redimensionar um array nos bastidores para você. (Se necessário, List <> é bastante inteligente sobre a escolha de tamanhos de matriz, por isso não é necessário normalmente.)

Arrays devem ser usados ​​de preferência para List quando a imutabilidade da própria coleção é parte do contrato entre o cliente e o código do provedor (não necessariamente a imutabilidade dos itens dentro da coleção) E quando IEnumerable não é adequado.

Por exemplo,

 var str = "This is a string"; var strChars = str.ToCharArray(); // returns array 

É claro que a modificação de “strChars” não irá alterar o object “str” ​​original, independentemente do conhecimento em nível de implementação do tipo subjacente de “str”.

Mas suponha que

 var str = "This is a string"; var strChars = str.ToCharList(); // returns List strChars.Insert(0, 'X'); 

Nesse caso, não fica claro apenas a partir desse snippet de código se o método de inserção irá ou não alterar o object “str” ​​original. Ele requer conhecimento de nível de implementação de String para fazer essa determinação, o que quebra a abordagem Design by Contract. No caso de String, não é grande coisa, mas pode ser um grande negócio em quase todos os outros casos. Definir a Lista como somente leitura ajuda, mas resulta em erros em tempo de execução, não em tempo de compilation.

Se eu sei exatamente quantos elementos vou precisar, digamos que eu preciso de 5 elementos e apenas 5 elementos, então eu uso uma matriz. Caso contrário, eu apenas uso uma List .

Na maioria das vezes, usando uma List seria suficiente. Uma List usa uma matriz interna para manipular seus dados e redimensiona automaticamente a matriz ao adicionar mais elementos à List que sua capacidade atual, o que torna mais fácil de usar do que uma matriz, onde você precisa saber a capacidade de antemão.

Consulte http://msdn.microsoft.com/en-us/library/ms379570(v=vs.80).aspx#datastructures20_1_topic5 para obter mais informações sobre Listas em C # ou apenas decompile System.Collections.Generic.List .

Se você precisa de dados multidimensionais (por exemplo, usando uma matriz ou em programação gráfica), você provavelmente iria com um array .

Como sempre, se a memory ou o desempenho forem um problema, meça! Caso contrário, você pode estar fazendo falsas suposições sobre o código.

Outra situação ainda não mencionada é quando uma pessoa terá um grande número de itens, cada um deles consistindo em um conjunto fixo de variables ​​relacionadas, mas independentes, unidas (por exemplo, as coordenadas de um ponto ou os vértices de um triângulo 3D). Uma matriz de estruturas de campo exposto permitirá que os seus elementos sejam modificados eficientemente “in place” – algo que não é possível com qualquer outro tipo de coleção. Como uma matriz de estruturas mantém seus elementos consecutivamente na RAM, os accesss sequenciais aos elementos da matriz podem ser muito rápidos. Em situações em que o código precisará fazer muitas passagens seqüenciais através de uma matriz, uma matriz de estruturas pode superar uma matriz ou outra coleção de referências de object de class por um fator de 2: 1; além disso, a capacidade de atualizar elementos no local pode permitir que uma matriz de estruturas supere qualquer outro tipo de coleção de estruturas.

Embora as matrizes não sejam redimensionáveis, não é difícil ter o armazenamento de código de uma referência de matriz junto com o número de elementos que estão em uso e replace a matriz por uma maior conforme necessário. Como alternativa, pode-se facilmente escrever código para um tipo que se comporta de maneira muito parecida com uma List mas expõe seu armazenamento de backup, permitindo assim que se diga MyPoints.Add(nextPoint); ou MyPoints.Items[23].X += 5; . Observe que o último não necessariamente lançaria uma exceção se o código tentasse acessar além do final da lista, mas o uso seria conceitualmente bastante similar ao List .

As listas no .NET são wrappers em arrays e usam um array internamente. A complexidade de tempo das operações nas listas é a mesma que seria com as matrizes, no entanto, há um pouco mais de sobrecarga com toda a funcionalidade / facilidade de uso das listas (como redimensionamento automático e os methods que vêm com a class de lista). Praticamente, eu recomendaria o uso de listas em todos os casos, a menos que haja uma razão convincente para não fazer isso, como se você precisasse escrever um código extremamente otimizado ou estivesse trabalhando com outro código criado em torno de matrizes.

Depende completamente dos contextos em que a estrutura de dados é necessária. Por exemplo, se você estiver criando itens para serem usados ​​por outras funções ou serviços usando List, é a maneira perfeita de realizá-lo.

Agora, se você tiver uma lista de itens e quiser apenas exibi-los, por exemplo, em uma matriz de página da Web, é o contêiner que você precisa usar.

Em vez de fazer uma comparação dos resources de cada tipo de dados, acho que a resposta mais pragmática é “as diferenças provavelmente não são importantes para o que você precisa realizar, especialmente porque elas implementam IEnumerable , portanto siga as convenções populares e use uma List até que você tenha uma razão para não, em que ponto você provavelmente terá sua razão para usar uma matriz sobre uma List “.

Na maior parte do tempo, no código gerenciado, você desejará que as collections sejam tão fáceis de trabalhar quanto possível, além de se preocupar com micro-otimizações.

Já que ninguém menciona: MyClass[] e List ambos implementam IList . Se você está pensando em qual deles aceitar como argumento, você pode declará-lo como IList para a conveniência dos chamadores. (por exemplo, Foo(IList foo) pode ser chamado como Foo(new[] { 1, 2, 3 }) ou Foo(new List { 1, 2, 3 }) )

Eles podem ser impopulares, mas eu sou fã de Arrays em projetos de jogos. – Velocidade de iteração pode ser importante em alguns casos, foreach em um Array tem significativamente menos sobrecarga se você não estiver fazendo muito por elemento – Adicionando e removendo não é tão difícil com funções auxiliares – É mais lento, mas em casos onde você o constrói apenas pode não importar – Na maioria dos casos, menos memory extra é desperdiçada (apenas realmente significativa com Arrays de structs) – Um pouco menos de lixo e pointers e perseguição de ponteiro

Dito isto, uso muito mais a Lista do que os Arrays na prática, mas cada um deles tem o seu lugar.

Seria bom se List fosse um tipo embutido, de modo que eles pudessem otimizar o wrapper e a sobrecarga de enumeração.