Tableau versus Liste<T>: Quand utiliser?
MyClass[] array;
List<MyClass> list;
Quels sont les scénarios quand l'un est préférable à l'autre? Et pourquoi?
- Les tableaux sont plutôt obsolète, comme on le voit dans un populaire de discussion ici. Aussi souligné ici, et par notre hôte le blog.
- Si je ne me trompe pas, la Liste<> a un tableau en tant que structure interne. Chaque fois que le tableau interne est rempli, il suffit de copier le contenu d'un tableau qui est le double de la taille (ou une autre constante de temps de la taille actuelle). en.wikipedia.org/wiki/Dynamic_array
- Ykok: Ce que vous dites semble à propos de droite, j'ai trouvé le code source de List<> ici.
- Faisant valoir que les tableaux sont obsolètes est peut-être un peu gras
InformationsquelleAutor Frederick The Fool | 2009-01-12
Vous devez vous connecter pour publier un commentaire.
Il est rare, en réalité, que vous ne souhaitez pas utiliser un tableau. Certainement utiliser un
List<T>
tout moment vous souhaitez ajouter/supprimer des données, depuis le redimensionnement des tableaux est cher. Si vous connaissez les données de longueur fixe, et que vous souhaitez micro-optimiser pour certains très spécifiques raison (après évaluation), puis un tableau peut être utile.List<T>
offre un beaucoup plus de fonctionnalités qu'un tableau (bien que LINQ evens un peu), et est presque toujours le bon choix. Sauf pourparams
arguments, bien sûr. ;-pComme un contre -
List<T>
est unidimensionnel; où-comme vous avez rectangulaire (etc) des tableaux commeint[,]
oustring[,,]
- mais il existe d'autres moyens de modélisation de ces données (si vous en avez besoin) dans un modèle objet.Voir aussi:
Cela dit, je fais une beaucoup de l'utilisation de tableaux dans mon protobuf-net projet; entièrement pour la performance:
byte[]
est à peu près indispensable pour l'encodage;byte[]
tampon que je remplis avant de les envoyer vers le flux sous-jacent (et v. v.); plus rapide queBufferedStream
etc;Foo[]
plutôt queList<Foo>
), puisque la taille est fixe une fois construit, et doit être très rapide.Mais c'est certainement une exception; pour la ligne générale de traitement des affaires, un
List<T>
gagne à chaque fois.IList<T>
ouIEnumerable<T>
- il permet à l'appelant de décider ce qu'ils veulent utiliser (T[]
ouList<T>
etc). LINQ largement soldes beaucoup de supplémentaireList<T>
fonctions (plus deIList<T>
).foreach
).Except for params arguments, of course ;-p
Pourquoi, sauf pour les params arguments? Pourriez-vous expliquer un peu?params
uniquement il existe pour les vecteurs; c'est donc l'un des endroits où il est plus naturel d'utiliser un tableau nu. Bien sûr, personnellement, je suis très anti-invisible-allocation, donc j'essaie d'éviterparams
en premier lieu.double[,]
,Point3D[,]
, et la comme. Vous avez toutes les ressources sur le point concernant les modèles d'objet pour cette utilisation, qui sont mieux que la plaine des tableaux? Mes tableaux sont généralement dense et ne pas les redimensionner ou les transformer. Merci!List<>
. Puisque les structures de données qui changent au fil du temps, de rendre le code difficile à comprendre, j'avais activement vous recommandons de ne pas utiliserList<>.Add
, sauf si vous avez donné un examen attentif; du tableau il suffit de retirer un plus source de bugs dans le code qui n'a pas besoin d'un redimensionnement dynamique (c'est à dire la plupart du code).foreach
etList<>.Add
. Autres code traite avec des collections de valeurs, et calcule les nouvelles collections de vieux. Ce code aime LINQ, et est de peu d'usage pour mutable collections. Cette réponse implicitement préfère les boucles de+de mutation au cours de constructions fonctionnelles, et je ne pense pas qu'une telle préférence devrait être implicite que fait la façon dont il est. La plupart des code je vois tend vers le fonctionnel, le calcul de nouvelles collections (ou les itérateurs) à partir de l'existant, des données inchangées.Add
méthode immédiatement évite la source n ° 1 d'une mauvaise utilisation accidentelle, et de l'expérience dans un grand projet, je peux dire que les bugs sont désagréables car (tout comme null-deref bugs) le code qui plante ou calcule la valeur faux est souvent éloignés de la source de l'erreur (le code qui a changé interne discbased qui était censé être immuable). TL;DR: Si vous allez le LINQ route, ce qui est le cas d'utilisation pourList<>
?List<>
si vous n'avez pas besoin de la mutabilité: ils sont plus rapides, utiliser moins de mémoire et éviter le plus commun mutable opération. Malheureusement, .NET ne fournit pas de comparable immuable array (il y a un package nuget pour le Système.Les Collections.Immuable, mais la matrice de mise en œuvre est encore préliminaire uniquement), et encore une fois il ne, pas tout le monde peut mettre à jour à la dernière .NET immédiatement et l'immutabilité wrapper ont des frais généraux. Dans l'ensemble: pour l'instant, l'ensemble est assez bon (et certainement mieux queList<>
non-mutation de cas d'utilisation.List<>
est donc approprié pour la mutation de collections, il est inapproprié pour les non-mutation des collections parce que le type de véhicule le mauvais message.ReadOnlyCollection<T>
serait d'envoyer ce message encore plus fortement.int[,]
est explicitement un tableau 2D.int[,,]
est explicitement un tableau 3d.int[][]
n'est cependant pas un "tableau 2d" - c'est un tableau 1D de tableaux 1D, aka un tableau en escalier. De mêmeList<List<int>>
n'est pas un 2D liste: c'est une liste de listes. Le point est que, dans le cas deint[,]
il y a un array, nous pouvons ainsi décrire les propriétés de l'1 tableau. Dans le cas deList<List<int>>
il y a n+1 listes; l'un est un 1D liste de listes, quand est-1D listes d'entiers. Oui, vous pouvez utiliser unList<List<int>>
pour exprimer les données en 2D, mais ce n'est pas la même chose. La sémantique de la matière.params
ou de garantie de taille fixe. Liste de traiter avec les redimensionner.Regex.split
Vraiment juste de répondre à ajouter un lien sur lequel je suis surpris n'a pas encore été mentionnés: Eric Lippert l'entrée de blog sur Des "tableaux considéré comme un peu dangereux."
Vous pouvez en juger par le titre qu'il suggère à l'aide de collections dans la mesure du possible - mais comme Marc souligne à juste titre, il y a beaucoup d'endroits où un tableau est vraiment la seule solution pratique.
Nonobstant les autres réponses recommander
List<T>
, vous aurez envie d'utiliser des tableaux lors de la manipulation:List<T>
ici plutôt que d'un tableau d'octets?Sauf si vous êtes vraiment intéressé à la performance, et par cela je veux dire, "Pourquoi êtes-vous à l'aide .Net au lieu de C++?" vous devriez coller avec la Liste des<>. C'est plus facile à maintenir et à faire tout le sale travail de redimensionnement d'un tableau derrière les coulisses pour vous. (Si nécessaire, une Liste<> est assez intelligent pour choisir la taille des matrices de sorte qu'il n'a pas besoin de d'habitude.)
Tableaux devrait être utilisée de préférence à la Liste lors de l'immutabilité de la collection elle-même est une partie du contrat entre le client & fournisseur de code (pas nécessairement l'immuabilité des éléments au sein de la collection) ET quand IEnumerable n'est pas adapté.
Par exemple,
Il est clair que la modification de la "strChars" ne sera pas la mutation de l'original "str" objet, indépendamment de la mise en œuvre des connaissances de niveau de "str"de type sous-jacent.
Mais supposons que
Dans ce cas, il n'est pas clair à partir de ce code-extrait de seul si la méthode d'insertion permettra ou non de la mutation de l'original "str" objet. Il nécessite la mise en place du niveau de connaissance de la Chaîne pour faire cette détermination, qui casse la Conception par Contrat approche. Dans le cas de la Chaîne, c'est pas une grosse affaire, mais il peut être un gros problème dans presque tous les autres cas. Réglage de la Liste de lecture seule aide, mais les résultats dans les erreurs d'exécution, et non pas au moment de la compilation.
To
va créer un objet qui n'a pas la possibilité de modifier l'instance d'origine, par opposition àstrChars as char[]
qui, si elle valide suggère que vous êtes maintenant en mesure de modifier l'objet original.Si je sais exactement comment beaucoup d'éléments que je vais avoir besoin d', dire que j'ai besoin de 5 éléments et seulement jamais 5 éléments, puis-je utiliser un tableau. Sinon je viens d'utiliser une Liste<T>.
La plupart du temps, à l'aide d'un
List
suffirait. UnList
utilise un tableau interne pour gérer ses données, et redimensionne automatiquement la matrice lors de l'ajout d'autres éléments à l'List
que sa capacité actuelle, ce qui rend plus facile à utiliser qu'un tableau, où vous avez besoin de connaître les capacités de l'avance.Voir http://msdn.microsoft.com/en-us/library/ms379570(v=vs. 80).aspx#datastructures20_1_topic5 pour plus d'informations sur les Listes en C# ou tout simplement décompiler
System.Collections.Generic.List<T>
.Si vous avez besoin de données multidimensionnelles (par exemple à l'aide d'une matrice ou dans les graphiques de programmation), vous devriez probablement aller avec un
array
à la place.Comme toujours, si la mémoire ou de la performance est un problème, de le mesurer! Sinon, vous pourriez faire de fausses hypothèses sur le code.
Une autre situation qui n'est pas encore mentionné, c'est que quand on va avoir un grand nombre d'éléments, dont chacun se compose d'un fixe tas de mais-variables indépendantes collés ensemble (par exemple, les coordonnées d'un point, ou les sommets d'un 3d triangle). Un tableau de l'exposé-structures sur le terrain permettra à l'un de ses éléments pour être efficace modifié "en place"--quelque chose qui n'est pas possible avec n'importe quel autre type de collection. Car un tableau de structures tient ses éléments de manière consécutive dans la mémoire RAM, séquentielle accède aux éléments d'un tableau peuvent être très rapides. Dans les situations où le code a besoin de faire de nombreux séquentielle passe à travers un tableau, un tableau de structures peuvent produire un tableau ou d'un autre groupe de la classe des références d'objet par un facteur de 2:1; de plus, la possibilité de mettre à jour les éléments en place peut permettre à un tableau de structures à surpasser tout autre type de collection de structures.
Bien que les tableaux ne sont pas redimensionnables, il n'est pas difficile d'avoir le code de stocker une référence de tableau avec le nombre d'éléments qui sont en cours d'utilisation, et de remplacer le tableau avec un plus grand un seul en tant que de besoin. Alternativement, on pourrait facilement écrire du code pour un type qui s'est comporté comme un
List<T>
mais exposé son magasin de sauvegarde, permettant ainsi à dire soitMyPoints.Add(nextPoint);
ouMyPoints.Items[23].X += 5;
. A noter que ce dernier ne serait pas nécessairement lever une exception si le code a tenté d'accéder au-delà de la fin de la liste, mais l'utilisation serait contraire être conceptuellement assez similaire àList<T>
.Point[] arr;
, il est possible pour le code-à-dire, par exemple,arr[3].x+=q;
. En utilisant par exempleList<Point> list
, il faudrait plutôt direPoint temp=list[3]; temp.x+=q; list[3]=temp;
. Il serait utile siList<T>
avait une méthodeUpdate<TP>(int index, ActionByRefRef<T,TP> proc, ref TP params)
. et les compilateurs pourrait se transformerlist[3].x+=q;
en{list.Update(3, (ref int value, ref int param)=>value+=param, ref q);
, mais pas une telle fonction existe.list[0].X += 3;
va ajouter 3 à la propriété X de le premier élément de la liste. Etlist
est unList<Point>
etPoint
est une classe avec des propriétés X et YListes .NET sont des wrappers sur des tableaux, et l'utilisation d'un tableau à l'interne. Le temps de la complexité des opérations sur les listes est le même que ce serait avec les tableaux, mais il est un peu plus frais avec toutes les fonctionnalités ajoutées /facilité d'utilisation des listes (comme le redimensionnement automatique et les méthodes de la classe list). Très bien, je recommande l'utilisation de listes dans tous les cas, sauf s'il existe une raison impérieuse pas de le faire, comme si vous avez besoin d'écrire très optimisé le code, ou de travailler avec un autre code qui est construit autour des tableaux.
Plutôt que de passer par une comparaison des caractéristiques de chaque type de données, je pense que le plus pragmatique réponse est "les différences ne sont probablement pas si important que cela pour ce que vous devez accomplir, surtout depuis qu'ils mettent en œuvre
IEnumerable
, afin de suivre la convention populaire et l'utilisation d'unList
jusqu'à ce que vous avez une raison de ne pas, à quel point vous aurez probablement la raison de votre utilisation d'un tableau sur uneList
."La plupart du temps dans la gestion de code que vous allez vouloir faveur des collections étant aussi facile à travailler que possible plus de se soucier de micro-optimisations.
Ils peuvent être impopulaires, mais je suis un fan de Tableaux dans des projets de jeux.
- Itération de la vitesse peut être important dans certains cas, foreach sur un Tableau a nettement moins de frais généraux si vous ne faites pas beaucoup par élément
- L'ajout et la suppression n'est pas difficile avec des fonctions d'assistance
- Son plus lent, mais dans le cas où vous ne construisez une fois qu'il ne peut pas d'importance
- Dans la plupart des cas, moins de la mémoire supplémentaire est perdue (le seul vraiment important avec des Tableaux de structures)
- Un peu moins de déchets et des pointeurs de pointeurs et de chasser
Cela étant dit, j'ai utiliser la Liste beaucoup plus souvent que les Matrices dans la pratique, mais ils ont chacun leur place.
Ce serait bien si la Liste où construit dans le type, afin qu'ils puissent optimiser l'emballage et l'énumération de frais généraux.
Remplissage d'une liste est plus facile que d'un tableau. Pour les tableaux, vous avez besoin de connaître la longueur exacte des données, mais pour les listes, la taille des données peut être tout. Et, vous pouvez convertir une liste dans un tableau.
Tableaux De Vs. Listes est un classique de la maintenabilité et de performances de problème. La règle de base que presque tous les développeurs suivent, c'est que vous pouvez tirer pour les deux, mais quand ils entrent en conflit, choisissez la facilité de maintenance sur les performances. L'exception à cette règle est lorsque la performance est déjà avéré être un problème. Si vous portez ce principe dans les Tableaux de Vs. Les listes, puis vous obtenez ceci:
Utilisation fortement typé des listes jusqu'à ce que vous frappez les problèmes de performance. Si vous rencontrez un problème de performance, de prendre une décision quant à savoir si le décrochage des tableaux seront bénéfiques pour votre solution avec des performances plus que ce sera au détriment de votre solution en termes de maintenance.
Car on ne mentionner: En C#, un tableau est une liste de.
Maclasse[]
etList<Maclasse>
à la fois de mettre en œuvreIList<Maclasse>
. (par exemple,void Foo(IList<int> foo)
peut être appelée commeFoo(new[] { 1, 2, 3 })
ouFoo(new List<int> { 1, 2, 3 })
)Donc, si vous écrivez une méthode qui accepte un
List<MyClass>
comme un argument, mais utilise seulement sous-ensemble de fonctionnalités, vous pouvez déclarer en tant queIList<MyClass>
la place pour les appelants confort.Détails:
List
, il n'implémente que laIList
interface.Il dépend entièrement du contexte dans lequel la structure de données est nécessaire. Par exemple, si vous créez des éléments qui seront utilisés par d'autres fonctions ou services à l'aide de la Liste est la meilleure façon de l'accomplir.
Maintenant, si vous avez une liste d'éléments et vous voulez juste pour les afficher, par exemple sur une page web tableau est le conteneur, vous devez utiliser.
IEnumerable<T>
- alors je peux les objets de flux plutôt que de les protéger.