142 votes

Comment initialiser une List<T> à une taille donnée (par opposition à la capacité) ?

.NET propose un conteneur de liste générique dont les performances sont presque identiques (voir la question sur les performances des tableaux et des listes). Cependant, ils sont très différents au niveau de l'initialisation.

Les tableaux sont très faciles à initialiser avec une valeur par défaut, et par définition ils ont déjà une certaine taille :

string[] Ar = new string[10];

ce qui permet d'attribuer en toute sécurité des éléments aléatoires, par exemple :

Ar[5]="hello";

avec une liste, les choses sont plus délicates. Je peux voir deux façons de faire la même initialisation, aucune n'est ce qu'on pourrait appeler élégante :

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

ou

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

Quel serait le moyen le plus propre ?

EDIT : Les réponses données jusqu'à présent font référence à la capacité, ce qui est autre chose que de pré-remplir une liste. Par exemple, sur une liste qui vient d'être créée avec une capacité de 10, on ne peut pas faire L[2]="une valeur".

EDIT 2 : Les gens se demandent pourquoi je veux utiliser les listes de cette façon, car ce n'est pas la façon dont elles sont censées être utilisées. Je vois deux raisons :

  1. On pourrait argumenter de manière tout à fait convaincante que les listes sont les tableaux de "nouvelle génération", ajoutant de la flexibilité sans presque aucune pénalité. On devrait donc les utiliser par défaut. Je signale qu'elles ne sont peut-être pas aussi faciles à initialiser.

  2. Ce que j'écris actuellement est une classe de base offrant une fonctionnalité par défaut dans le cadre d'une structure plus large. Dans la fonctionnalité par défaut que je propose, la taille de la liste est connue à l'avance et j'aurais donc pu utiliser un tableau. Cependant, je veux offrir à n'importe quelle classe de base la possibilité de l'étendre dynamiquement et j'opte donc pour une liste.

1 votes

"EDIT : Les réponses données jusqu'à présent font référence à la capacité, ce qui est autre chose que de pré-remplir une liste. Par exemple, sur une liste qui vient d'être créée avec une capacité de 10, on ne peut pas faire L[2]="somevalue"". Compte tenu de cette modification, vous devriez peut-être reformuler le titre de la question...

0 votes

Mais, quelle est l'utilité de pré-remplir une liste avec des valeurs vides, car c'est ce que le topicstarter essaie de faire ?

0 votes

Frederik : Exactement. Quand cela serait-il nécessaire... jamais ?

7voto

Frederik Gheysels Points 36354

Pourquoi utiliser une liste si vous voulez l'initialiser avec une valeur fixe ? Je peux comprendre que - pour des raisons de performance - vous vouliez lui donner une capacité initiale, mais l'un des avantages d'une liste par rapport à un tableau ordinaire n'est-il pas qu'elle peut croître si nécessaire ?

Quand tu fais ça :

List<int> = new List<int>(100);

Vous créez une liste dont la capacité est de 100 entiers. Cela signifie que votre liste n'aura pas besoin de s'agrandir avant que vous n'ayez ajouté le 101e élément. Le tableau sous-jacent de la liste sera initialisé avec une longueur de 100.

1 votes

"Pourquoi utilisez-vous une liste si vous voulez l'initialiser avec une valeur fixe" Un bon point.

8 votes

Il a demandé une liste dans laquelle chaque élément était initialisé et la liste avait une taille, pas seulement une capacité. Cette réponse est incorrecte en l'état actuel des choses.

0 votes

La question appelle une réponse, pas une critique de la question posée. Il y a parfois une raison de procéder de cette manière, plutôt que d'utiliser un tableau. Si vous souhaitez savoir pourquoi, vous pouvez poser une question à ce sujet sur Stack Overflow.

5voto

Greg D Points 24218

Vous semblez mettre l'accent sur la nécessité d'une association positionnelle avec vos données, alors un tableau associatif ne serait-il pas plus approprié ?

Dictionary<int, string> foo = new Dictionary<int, string>();
foo[2] = "string";

0 votes

C'est répondre à une question différente de celle qui est posée.

4voto

Welbog Points 32952

Initialiser le contenu d'une liste comme ça n'est pas vraiment ce à quoi servent les listes. Les listes sont conçues pour contenir des objets. Si vous souhaitez associer des nombres particuliers à des objets particuliers, envisagez d'utiliser une structure de paires clé-valeur comme une table de hachage ou un dictionnaire plutôt qu'une liste.

1 votes

Cela ne répond pas à la question, mais donne simplement une raison pour qu'elle ne soit pas posée.

2voto

La réponse acceptée (celle qui est marquée d'une coche verte) présente un problème.

Le problème :

var result = Lists.Repeated(new MyType(), sizeOfList);
// each item in the list references the same MyType() object
// if you edit item 1 in the list, you are also editing item 2 in the list

Je recommande de modifier la ligne ci-dessus pour effectuer une copie de l'objet. Il y a beaucoup d'articles différents à ce sujet :

Si vous souhaitez initialiser chaque élément de votre liste avec le constructeur par défaut, plutôt qu'avec NULL, ajoutez la méthode suivante :

public static List<T> RepeatedDefaultInstance<T>(int count)
    {
        List<T> ret = new List<T>(count);
        for (var i = 0; i < count; i++)
        {
            ret.Add((T)Activator.CreateInstance(typeof(T)));
        }
        return ret;
    }

1 votes

Ce n'est pas un "problème" - c'est le comportement normal de la copie des références. Sans connaître la situation, vous ne pouvez pas savoir s'il est approprié de copier l'objet. La question n'est pas de savoir si les listes doivent ou non être alimentées par des copies - il s'agit d'initialiser une liste avec une capacité. Je vais préciser ma réponse en termes de comportement qu'elle fait mais je ne pense pas que ce soit un problème dans le contexte de cette question.

0 votes

@JonSkeet, je répondais à l'aide statique, qui convient aux types primitifs mais pas aux types de référence. Un scénario où une liste est initialisée avec le même élément référencé ne semble pas correct. Dans ce scénario, pourquoi même avoir la liste si chaque élément de celle-ci pointe vers le même objet sur le tas.

0 votes

Exemple de scénario : vous voulez remplir une liste de chaînes de caractères, initialement avec une entrée "Inconnu" pour chaque élément, puis vous modifiez la liste pour des éléments spécifiques. Dans ce cas, il est tout à fait raisonnable que toutes les valeurs "Inconnu" soient des références à la même chaîne. Il serait inutile de cloner la chaîne à chaque fois. Le fait de remplir une chaîne de caractères avec plusieurs références au même objet n'est pas "bon" ou "mauvais" dans un sens général. Tant que les lecteurs savent quel est le comportement, c'est à eux de décider s'il répond aux exigences de la norme. leur cas d'utilisation spécifique .

1voto

pdx mobilist Points 2821

Cela dépend vraiment de la raison pour laquelle vous voulez l'initialiser. Je ne suis pas sûr que l'initialiser avec un certain nombre d'éléments vides ou nuls soit utile. L'avantage des listes est qu'elles peuvent croître selon les besoins.

Le constructeur de la liste prend un paramètre de capacité qui peut être utilisé pour la remplir initialement.

List<string> = new List<string>(10);

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X