Como inicializar uma lista para um determinado tamanho (em oposição à capacidade)?

O .NET oferece um contêiner de lista genérica cujo desempenho é quase idêntico (consulte a pergunta Desempenho de matrizes x listas). No entanto, eles são bastante diferentes na boot.

Os arrays são muito fáceis de inicializar com um valor padrão e, por definição, eles já possuem determinado tamanho:

string[] Ar = new string[10]; 

Que permite atribuir com segurança itens randoms, digamos:

 Ar[5]="hello"; 

com as coisas da lista são mais complicadas. Eu posso ver duas maneiras de fazer a mesma boot, nenhuma das quais é o que você chamaria de elegante:

 List L = new List(10); for (int i=0;i<10;i++) L.Add(null); 

ou

 string[] Ar = new string[10]; List L = new List(Ar); 

O que seria um caminho mais limpo?

EDIT: As respostas até agora referem-se a capacidade, que é outra coisa do que preencher previamente uma lista. Por exemplo, em uma lista recém criada com uma capacidade de 10, não se pode fazer L[2]="somevalue"

EDIT 2: As pessoas perguntam por que eu quero usar listas dessa maneira, como não é o modo como elas devem ser usadas. Eu posso ver duas razões:

  1. Poder-se-ia argumentar bastante convincentemente que as listas são as matrizes da “próxima geração”, adicionando flexibilidade com quase nenhuma penalidade. Portanto, deve-se usá-los por padrão. Estou apontando que eles podem não ser tão fáceis de inicializar.

  2. O que estou escrevendo atualmente é uma class base que oferece funcionalidade padrão como parte de uma estrutura maior. Na funcionalidade padrão que ofereço, o tamanho da lista é conhecido em avançado e, portanto, eu poderia ter usado uma matriz. No entanto, quero oferecer a qualquer class base a chance de estendê-la dinamicamente e, portanto, opto por uma lista.

Eu não posso dizer que preciso disso com muita freqüência – você poderia dar mais detalhes do porquê você quer isso? Eu provavelmente colocaria isso como um método estático em uma class auxiliar:

 public static class Lists { public static List RepeatedDefault(int count) { return Repeated(default(T), count); } public static List Repeated(T value, int count) { List ret = new List(count); ret.AddRange(Enumerable.Repeat(value, count)); return ret; } } 

Você poderia usar Enumerable.Repeat(default(T), count).ToList() mas isso seria ineficiente devido ao redimensionamento do buffer.

EDIT: Como observado nos comentários, você poderia fazer Repeated usar um loop para preencher a lista se você quisesse. Isso seria um pouco mais rápido também. Pessoalmente, eu acho o código usando Repeat mais descritivo, e suspeito que no mundo real a diferença de desempenho seria irrelevante, mas sua milhagem pode variar.

 List L = new List ( new string[10] ); 

Use o construtor que usa um int (“capacity”) como argumento:

 List = new List(10); 

EDIT: devo acrescentar que eu concordo com Frederik. Você está usando a Lista de uma maneira que vai contra todo o raciocínio por trás de usá-la em primeiro lugar.

EDIT2:

EDIT 2: O que estou escrevendo atualmente é uma class base oferecendo funcionalidade padrão como parte de uma estrutura maior. Na funcionalidade padrão que ofereço, o tamanho da lista é conhecido em avançado e, portanto, eu poderia ter usado uma matriz. No entanto, quero oferecer a qualquer class base a chance de estendê-la dinamicamente e, portanto, opto por uma lista.

Por que alguém precisaria saber o tamanho de uma lista com todos os valores nulos? Se não houver valores reais na lista, eu esperaria que o comprimento fosse 0. De qualquer forma, o fato de que isso é claudicante demonstra que está indo contra o uso pretendido da class.

Por que você está usando uma lista se quiser inicializá-la com um valor fixo? Eu posso entender isso – por causa do desempenho – você quer dar a ele uma capacidade inicial, mas não é uma das vantagens de uma lista sobre um array regular que pode crescer quando necessário?

Quando você faz isso:

 List = new List(100); 

Você cria uma lista cuja capacidade é 100 inteiros. Isso significa que sua Lista não precisará “crescer” até você adicionar o 101º item. O array subjacente da lista será inicializado com um comprimento de 100.

Inicializando o conteúdo de uma lista como essa não é realmente o que as listas são para. As listas são projetadas para armazenar objects. Se você deseja mapear determinados números para objects específicos, considere o uso de uma estrutura de par de valores-chave como uma tabela de hash ou um dictionary em vez de uma lista.

Se você quiser inicializar a lista com N elementos de algum valor fixo:

 public List InitList(int count, T initValue) { return Enumerable.Repeat(initValue, count).ToList(); } 

Você parece estar enfatizando a necessidade de uma associação posicional com seus dados, portanto, um arranjo associativo não seria mais adequado?

 Dictionary foo = new Dictionary(); foo[2] = "string"; 

Crie uma matriz com o número de itens que você deseja primeiro e, em seguida, converta a matriz em uma lista.

 int[] fakeArray = new int[10]; List list = fakeArray.ToList(); 

Isso realmente depende do motivo pelo qual você deseja inicializá-lo. Não tenho certeza se inicializá-lo com um certo número de elementos vazios ou nulos é útil. A vantagem das listas é que elas podem crescer conforme necessário.

O construtor de lista usa um parâmetro de capacidade que pode ser usado para preenchê-lo inicialmente.

 List = new List(10); 
 string [] temp = new string[] {"1","2","3"}; List temp2 = temp.ToList(); 

Você pode usar o Linq para inicializar sua lista com um valor padrão. (Semelhante à resposta de David B. )

 var defaultStrings = (new int[10]).Select(x => "my value").ToList(); 

Vá um passo além e inicialize cada string com valores distintos “string 1”, “string 2”, “string 3”, etc:

 int x = 1; var numberedStrings = (new int[10]).Select(x => "string " + x++).ToList(); 

Um aviso sobre IList: MSDN IList Comentários : “IList implementações se enquadram em três categorias: somente leitura, tamanho fixo e tamanho de variável. (…). Para a versão genérica dessa interface, consulte System.Collections.Generic.IList . ”

IList não herda de IList (mas List implementa IList e IList ), mas é sempre de tamanho variável . Desde o .NET 4.5, também temos o IReadOnlyList mas o AFAIK, não existe uma lista genérica de tamanho fixo que seria o que você está procurando.

Esta é uma amostra que usei para o teste da minha unidade. Eu criei uma lista de objects de class. Então usei o forloop para adicionar o número ‘X’ de objects que estou esperando do serviço. Desta forma, você pode adicionar / inicializar uma lista para qualquer tamanho.

 public void TestMethod1() { var expected = new List(); for (int i = 0; i < 22; i++)//You add empty initialization here { var temp = new DotaViewer.Interface.DotaHero(); expected.Add(temp); } var nw = new DotaHeroCsvService(); var items = nw.GetHero(); CollectionAssert.AreEqual(expected,items); } 

Espero que eu tenha ajudado vocês.

Um pouco tarde, mas a primeira solução que você propôs parece muito mais limpa para mim: você não aloca memory duas vezes. O construtor Even List precisa fazer um loop através do array para copiá-lo; nem sequer sabe de antemão que existem apenas elementos nulos no interior.

1. – aloca o N-loop N Cost: 1 * aloca (N) + N * loop_iteration

2. – alocar N – alocar N + loop () Custo: 2 * alocar (N) + N * loop_iteration

No entanto alocação de lista de loops pode ser mais rápido desde que a lista é uma class interna, mas c # é compilado jit sooo …