Quelles sont les différences entre les tableaux multidimensionnels double[,]
et les tableaux de tableaux double[][]
en C #?
S'il y a une différence, quelle est la meilleure utilisation pour chacun?
Quelles sont les différences entre les tableaux multidimensionnels double[,]
et les tableaux de tableaux double[][]
en C #?
S'il y a une différence, quelle est la meilleure utilisation pour chacun?
double[,]
est un tableau rectangulaire, alors qu'ildouble[][]
est connu sous le nom de «tableau dentelé». La première aura le même nombre de "colonnes" pour chaque ligne, tandis que la seconde aura (potentiellement) un nombre différent de "colonnes" pour chaque ligne.Réponses:
Les tableaux de tableaux (tableaux dentelés) sont plus rapides que les tableaux multidimensionnels et peuvent être utilisés plus efficacement. Les tableaux multidimensionnels ont une syntaxe plus agréable.
Si vous écrivez du code simple à l'aide de tableaux irréguliers et multidimensionnels, puis inspectez l'assembly compilé avec un désassembleur IL, vous verrez que le stockage et la récupération à partir de tableaux dentelés (ou unidimensionnels) sont de simples instructions IL tandis que les mêmes opérations pour les tableaux multidimensionnels sont la méthode invocations toujours plus lentes.
Considérez les méthodes suivantes:
Leur IL sera le suivant:
Lorsque vous utilisez des tableaux irréguliers, vous pouvez facilement effectuer des opérations telles que l'échange de ligne et le redimensionnement de ligne. Dans certains cas, l'utilisation de tableaux multidimensionnels sera peut-être plus sûre, mais même Microsoft FxCop indique que les tableaux irréguliers doivent être utilisés au lieu de multidimensionnels lorsque vous les utilisez pour analyser vos projets.
la source
Un tableau multidimensionnel crée une belle disposition de mémoire linéaire tandis qu'un tableau irrégulier implique plusieurs niveaux supplémentaires d'indirection.
La recherche de la valeur
jagged[3][6]
dans un tableau irréguliervar jagged = new int[10][5]
fonctionne comme ceci: recherchez l'élément à l'index 3 (qui est un tableau) et recherchez l'élément à l'index 6 dans ce tableau (qui est une valeur). Pour chaque dimension dans ce cas, il existe une recherche supplémentaire (il s'agit d'un modèle d'accès à la mémoire coûteux).Un tableau multidimensionnel est disposé linéairement en mémoire, la valeur réelle est trouvée en multipliant ensemble les index. Cependant, étant donné le tableau
var mult = new int[10,30]
, laLength
propriété de ce tableau multidimensionnel renvoie le nombre total d'éléments, c'est-à-dire 10 * 30 = 300.La
Rank
propriété d'un tableau dentelé est toujours 1, mais un tableau multidimensionnel peut avoir n'importe quel rang. LaGetLength
méthode de n'importe quel tableau peut être utilisée pour obtenir la longueur de chaque dimension. Pour le tableau multidimensionnel dans cet exemple,mult.GetLength(1)
renvoie 30.L'indexation du tableau multidimensionnel est plus rapide. Par exemple, étant donné le tableau multidimensionnel dans cet exemple
mult[1,7]
= 30 * 1 + 7 = 37, obtenez l'élément à cet index 37. Il s'agit d'un meilleur modèle d'accès à la mémoire car un seul emplacement de mémoire est impliqué, qui est l'adresse de base du tableau.Un tableau multidimensionnel alloue donc un bloc de mémoire continue, tandis qu'un tableau dentelé n'a pas à être carré, par exemple
jagged[1].Length
n'a pas à être égaljagged[2].Length
, ce qui serait vrai pour tout tableau multidimensionnel.Performance
Les tableaux multidimensionnels en termes de performances devraient être plus rapides. Beaucoup plus rapide, mais en raison d'une implémentation CLR vraiment mauvaise, ils ne le sont pas.
La première ligne est le minutage des tableaux irréguliers, la seconde montre les tableaux multidimensionnels et la troisième, c'est comme ça que ça devrait être. Le programme est illustré ci-dessous, pour info, il a été testé en mono. (Les horaires des fenêtres sont très différents, principalement en raison des variations de mise en œuvre du CLR).
Sur les fenêtres, les synchronisations des tableaux irréguliers sont largement supérieures, à peu près la même que ma propre interprétation de ce à quoi devrait ressembler le tableau multidimensionnel, voir 'Single ()'. Malheureusement, le compilateur JIT de Windows est vraiment stupide, et cela rend malheureusement ces discussions sur les performances difficiles, il y a trop d'incohérences.
Ce sont les timings que j'ai obtenus sur les fenêtres, même chose ici, la première ligne est des tableaux irréguliers, le deuxième multidimensionnel et le troisième ma propre implémentation du multidimensionnel, notez à quel point cela est plus lent sur les fenêtres par rapport au mono.
Code source:
la source
Autrement dit, les tableaux multidimensionnels sont similaires à une table dans un SGBD.
Array of Array (tableau dentelé) permet à chaque élément de contenir un autre tableau du même type de longueur variable.
Donc, si vous êtes sûr que la structure des données ressemble à une table (lignes / colonnes fixes), vous pouvez utiliser un tableau multidimensionnel. Les tableaux dentelés sont des éléments fixes et chaque élément peut contenir un tableau de longueur variable
Par exemple, le pseudo-code:
Considérez ce qui précède comme un tableau 2x2:
Considérez ce qui précède comme chaque ligne ayant un nombre variable de colonnes:
la source
Préface: Ce commentaire est destiné à répondre à la réponse fournie par okutane , mais en raison du système de réputation stupide de SO, je ne peux pas l'afficher à sa place.
Votre affirmation selon laquelle l'une est plus lente que l'autre en raison des appels de méthode n'est pas correcte. L'un est plus lent que l'autre en raison d'algorithmes de vérification des limites plus compliqués. Vous pouvez facilement vérifier cela en regardant non pas l'IL, mais l'assembly compilé. Par exemple, sur mon installation 4.5, accéder à un élément (via un pointeur dans edx) stocké dans un tableau à deux dimensions pointé par ecx avec des index stockés dans eax et edx ressemble à ceci:
Ici, vous pouvez voir qu'il n'y a pas de surcharge des appels de méthode. La vérification des limites est juste très compliquée grâce à la possibilité d'index non-zéro, qui n'est pas une fonctionnalité proposée avec des tableaux irréguliers. Si nous supprimons les sous, cmp et jmps pour les cas non nuls, le code se résout à peu près à
(x*y_max+y)*sizeof(ptr)+sizeof(array_header)
. Ce calcul est à peu près aussi rapide (une multiplication pourrait être remplacée par un décalage, car c'est la raison pour laquelle nous choisissons des octets à dimensionner en puissances de deux bits) comme toute autre chose pour l'accès aléatoire à un élément.Une autre complication est qu'il existe de nombreux cas où un compilateur moderne optimisera la vérification des limites imbriquées pour l'accès aux éléments tout en itérant sur un tableau à une dimension. Le résultat est un code qui fait simplement avancer un pointeur d'index sur la mémoire contiguë du tableau. L'itération naïve sur des tableaux multidimensionnels implique généralement une couche supplémentaire de logique imbriquée, de sorte qu'un compilateur est moins susceptible d'optimiser le fonctionnement. Ainsi, même si la surcharge de vérification des limites de l'accès à un seul élément est amortie à un temps d'exécution constant en ce qui concerne les dimensions et les tailles des tableaux, un cas de test simple pour mesurer la différence peut prendre plusieurs fois plus de temps à s'exécuter.
la source
Je voudrais mettre à jour cela, car dans .NET Core, les tableaux multidimensionnels sont plus rapides que les tableaux irréguliers . J'ai exécuté les tests de John Leidegren et voici les résultats sur la prévisualisation 2. de NET Core 2.0. J'ai augmenté la valeur de la dimension pour rendre les influences possibles des applications d'arrière-plan moins visibles.
J'ai regardé dans les démontages et c'est ce que j'ai trouvé
jagged[i][j][k] = i * j * k;
34 instructions nécessaires pour exécutermulti[i, j, k] = i * j * k;
11 instructions nécessaires pour exécutersingle[i * dim * dim + j * dim + k] = i * j * k;
besoin de 23 instructions pour exécuterJe n'ai pas pu identifier pourquoi les tableaux unidimensionnels étaient encore plus rapides que multidimensionnels, mais je suppose que cela a à voir avec une optimisation effectuée sur le processeur
la source
Les tableaux multidimensionnels sont des matrices à (n-1) dimensions.
Il en
int[,] square = new int[2,2]
est de même de la matrice carrée 2x2,int[,,] cube = new int [3,3,3]
est une matrice cubique carrée 3x3. La proportionnalité n'est pas requise.Les tableaux dentelés ne sont que des tableaux de tableaux - un tableau où chaque cellule contient un tableau.
Les MDA sont donc proportionnels, JD ne l'est peut-être pas! Chaque cellule peut contenir un tableau de longueur arbitraire!
la source
Cela peut avoir été mentionné dans les réponses ci-dessus, mais pas explicitement: avec un tableau dentelé, vous pouvez utiliser
array[row]
pour référencer toute une ligne de données, mais cela n'est pas autorisé pour les tableaux multi-d.la source
En plus des autres réponses, notez qu'un tableau multidimensionnel est alloué comme un gros objet volumineux sur le tas. Cela a quelques implications:
<gcAllowVeryLargeObjects>
des tableaux multidimensionnels bien avant que le problème ne se pose si vous n'utilisez que des tableaux irréguliers.la source
J'analyse des fichiers .il générés par ildasm pour créer une base de données d'assassinats, de classes, de méthodes et de procédures stockées à utiliser pour effectuer une conversion. Je suis tombé sur ce qui suit, ce qui a brisé mon analyse.
Le livre Expert .NET 2.0 IL Assembler, de Serge Lidin, Apress, publié en 2006, chapitre 8, Types et signatures primitifs, pp. 149-150 explique.
<type>[]
est appelé un vecteur de<type>
,<type>[<bounds> [<bounds>**] ]
est appelé un tableau de<type>
**
les moyens peuvent être répétés, les[ ]
moyens sont facultatifs.Exemples: Let
<type> = int32
.1)
int32[...,...]
est un tableau bidimensionnel de bornes inférieures et de tailles non définies2)
int32[2...5]
est un tableau unidimensionnel de borne inférieure 2 et de taille 4.3)
int32[0...,0...]
est un tableau bidimensionnel de bornes inférieures 0 et de taille non définie.À M
la source