9
votes

Rebase un tableau basé sur 1 en C #

J'ai un tableau en C # qui est basé sur 1 (généré à partir d'un appel à get_value pour une gamme Excel Je reçois un tableau 2D par exemple xxx

ceci apparaît comme une matrice par exemple Exceldata [1..20,1..5]

Y a-t-il un moyen de dire Le compilateur pour la rebase de sorte que je n'ai pas besoin d'ajouter 1 des compteurs en boucle tout le temps? xxx

Il rend les choses moins lisibles depuis lors, une matrice pour écrire le tableau sera zéro à base de zéro.


5 commentaires

Les tableaux en C # sont toujours 0 à base, vous voulez dire que vos données sont basées sur 1?


Les tableaux déclarés dans le code source C # sont toujours à base de 0, mais le CLR prend en charge les tableaux avec des limites inférieures arbitraires.


Les tableaux créés en C # peuvent bien être zéro, mais je pense que je suis correct en indiquant que la matrice ici est basée sur 1 - Si vous essayez d'accéder à ExcelData [0,0], l'incexoutofrangeException est lancée. .


Peut-être qu'une question stupide, mais avez-vous validé que Exceldata a des données dedans?


@ Lmoser - Pas une question stupide, relavente mais ne faisant pas partie de cette question. Merci pour 3 façons excellentes et différentes de résoudre le problème - le problème est maintenant que cela ne permet que 1 'correct' réponse! 1. Copiez la matrice sur une (@andrew Hare) 2. Ajouter un deuxième index (pour la rangée Int = 0, Excelrow = 1; rangée <...; rangée ++, Excelrow ++) (@jason) 3. Enveloppez le Array et décalage dans la nouvelle classe (@Darren Thomas) dans la réévaluation à la lumière de ces trois que j'ai choisi l'option 1 (et ont maintenant écrit des emballages pour toutes les fonctions de la gamme Excel) afin que tout dans mon code soit à zéro.


8 Réponses :


10
votes

Pourquoi ne pas simplement changer votre index? xxx

edit: Voici une méthode d'extension qui créerait un nouveau tableau basé sur zéro de votre original (essentiellement, cela crée simplement un nouveau tableau qui est un élément plus petit et copie à ce nouveau tableau Tous les éléments, mais le premier élément que vous sautez actuellement de toute façon): xxx

qui étant dit que vous devez considérer si la pénalité (même légère ) La création d'un nouveau tableau vaut la peine d'améliorer la lisibilité du code. Je ne fais pas de jugement (ça vaut vraiment la peine) Je m'assure simplement que vous ne courez pas avec ce code s'il blesse la performance de votre application.


2 commentaires

Je ne peux pas croire que l'arbre de nous a posté la même réponse en même temps :)


Désolé - le code que j'ai fourni est trop simple - la rangée est utilisée ailleurs dans la boucle pour une boucle de comptage zéro.



1
votes

Changer le compteur de boucle trop difficile pour vous?

for (int Row = 1; Row <= MaxRows; Row++)


1 commentaires

Pas besoin d'être trop condescendant - voir les modifications apportées à la question initiale (d'autres ont dit la même chose légèrement de manière plus constructive) ...



3
votes

Pourquoi ne pas utiliser:

for (int Row = 1; Row <= MaxRows; Row++) {


0 commentaires

6
votes

Créer un wrapper pour le tableau ExcelData avec un Ceci [] indexeur et reconstituez la logique. Quelque chose comme: xxx


1 commentaires

J'aime cette solution parce que vous pouvez le rendre dynamique. J'ai ajouté un paramètre "Index de démarrage" au constructeur afin que cette classe puisse être utilisée pour les matrices à base de 1 et 0. J'ai aussi ajouté rowcount & Columncount au lieu d'avoir à spécifier array.getlength (x)



6
votes

Étant donné que vous avez besoin rangée code> pour rester as-is (basé sur vos commentaires), vous pouvez simplement introduire une autre variable de boucle:

List<string> RowHeadings = new List<string>();
string [,] Results = new string[MaxRows, 1]
for (int Row = 0, SrcRow = 1; SrcRow <= MaxRows; Row++, SrcRow++) {
    if (ExcelData[SrcRow, 1] != null)
        RowHeadings.Add(ExcelData[SrcRow, 1]);
        ...
        ...
        Results[Row, 0] = ExcelData[SrcRow, 1];
}


0 commentaires

0
votes

Je suis d'accord que travailler avec des tableaux de base-1 de .net peut être un problème. Il est également potentiellement sujet aux erreurs, car vous devez effectuer un changement mentalement à chaque fois que vous l'utilisez, ainsi que correctement, rappelez-vous que les situations seront la base 1 et qui sera la base 0.

L'approche la plus performante consiste à simplement Faites de ces changements mentaux et indexez de manière appropriée, en utilisant la base-1 ou la base-0 selon les besoins. p>

Je préfère personnellement convertir les matrices de base bidimensionnelles-1 en deux tableaux de base dimensionnelle-0. Malheureusement, cela nécessite le succès de la performance de la copie sur la matrice à un nouveau tableau, car il n'ya aucun moyen de renoncer à une matrice en place. P>

Voici une méthode d'extension qui peut le faire pour le 2D Les matières retournées par Excel: p> xxx pré>

et vous pouvez ensuite l'utiliser comme ceci: p>

object[,] array2DBase1 = (object[,]) MySheet.UsedRange.get_Value(Type.Missing);

object[,] array2DBase0 = array2DBase1.CloneBase0();

for (int row = 0; row < array2DBase0.GetLength(0); row++) 
{
    for (int column = 0; column < array2DBase0.GetLength(1); column++) 
    {
        // Your code goes here...
    }
}


4 commentaires

Merci - une optimisation, ayant validé les longueurs, vous pouvez utiliser System.Array.copy (de, à, la longueur) qui (vraisemblablement?) copie le tableau 2D plus efficacement.


C'est une bonne idée, sauf que vous ne pouvez pas. La méthode "Array.copy" fonctionne uniquement avec des tableaux 1 dimensions, tandis que le tableau renvoyé par Excel.Range.get_Value est un tableau en deux dimensions. La méthode de l'extension doit donc renvoyer Tresult [] basée sur Tsource [] et ne peut pas utiliser «Array.copy». Pas le choix!


Au fait, j'utilise cette approche pour tout mon code lorsqu'il s'agit de rédiger des tableaux de base-1 renvoyés par Excel. Je suppose que je ralentis tout mon code, mais pas tellement que j'ai remarqué, et la capacité de toujours traiter dans les tableaux de base-0 aide vraiment à me garder sain d'esprit. :)


Je sais que c'est vieux, mais vous pouvez utiliser Array.copy avec des tableaux 2D si vous modifiez le nombre de lignes et non de colonnes. Les matrices 2D sont aménagées séquentiellement en mémoire, de sorte que si les colonnes ne changent pas, l'hypothèse de l'endroit où la rangée se termine et le prochain commence toujours.



-1
votes

Vous pouvez utiliser un composant compatible 3ème partie Excel, tel que tableur au point de vue pour .NET qui a .NET sympathique API - y compris une indexation basée sur les API telle que Irange [int Rowindex, int colindex].

Ces composants seront également beaucoup plus rapides que l'API Excel dans presque tous les cas.

Clause de non-responsabilité: I PROPRETHEEPHEEARAIRE LLC


2 commentaires

Merci, bien que semble cher pour tout ce dont j'ai besoin actuellement (un ensemble d'emballages) - il n'existe pas de mention de marshalling que j'ai trouvé - aurais-je toujours besoin de gérer cela ou de la maintien de la feuille de calcul?


SpreadsheetGear n'est pas simplement une enveloppe pour Excel, mais un assemblage sécurisé .NET écrit en C #. Il n'utilise pas COMTEROP pour rien. Il ne repose pas sur Excel. C'est une composante de feuille de calcul compatible Excel avec son propre calcul, édition, formatage, rendu, etc ... moteur. Dans de nombreux cas, les clients nous disent que les applications accélèrent considérablement lorsqu'ils passent de COMT INTEROP / Excel Automation à SpreadsheetGear. Vous êtes également libéré de vous inquiéter de la version d'Excel que vos utilisateurs.



0
votes

pour les matrices basées sur 1 et les opérations de gamme Excel ainsi que les fonctions UDF (SharePoint), j'utilise cette fonction utilitaire xxx

utilisation xxx p > La première fonction est visible et acceptera une gamme Excel ou un appel en chaîné d'une autre fonction (l'appel en chaîne renvoie un tableau d'objet basé sur 1), le second appel est activé pour Excel Services à SharePoint. Toute la logique est dans la deuxième fonction. Dans cet exemple, nous sommes simplement reformatant une plage pour remplacer zéro avec String.empty.


0 commentaires