IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

C# Discussion :

Convertir un nombre dans une "base" où le zéro n'existe pas


Sujet :

C#

  1. #1
    Expert confirmé
    Avatar de StringBuilder
    Homme Profil pro
    Chef de projets
    Inscrit en
    Février 2010
    Messages
    4 197
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Chef de projets
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2010
    Messages : 4 197
    Billets dans le blog
    1
    Par défaut Convertir un nombre dans une "base" où le zéro n'existe pas
    Le bloc qui suit concerne une question qui n'a plus lieu d'être (et qui a trouvé sa réponse).

    Allez directement au poste 4, où j'expose mon problème pour déterminer la représentation d'un nombre décimal sous forme de lettres, à la sauce Excel (la numérotation des colonnes).

    ----------------------------------------------

    Bonjour,

    C'est plus un problème d'algo qu'autrechose... voir même de mathématique.

    Si je désire représenter le nombre "50" (base décimale) en base 8 (octale), je sais le faire de la façon suivante :

    50 % 8 = 2 ; 50 / 8 = 6
    6 % 8 = 6 ; 6 / 8 = 0
    => 62

    Je sais en même temps qu'il me faut 2 chiffres.

    Pour déterminer le nombre de chiffres, d'un point de vue algo, je vois donc comment faire :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    int val = 50;
    int base = 8;
    int nbDigits = 0;
     
    while (val > 0)
    {
       nbDigits++;
       val /= base;
    }
    Sauf que je trouve que c'est loin d'être performant.

    En effet, il me semble qu'il existe une fonction mathématique qui permet de dire combien de fois on peut diviser un nombre par un autre, mais pas moyen de mettre la main dessus

    J'ai cru un moment que c'était la fonction puissance avec -base ou 1/base, mais ce n'est visiblement pas ça.

  2. #2
    Inactif  
    Homme Profil pro
    Chef de projet NTIC
    Inscrit en
    Janvier 2007
    Messages
    6 604
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 64
    Localisation : France

    Informations professionnelles :
    Activité : Chef de projet NTIC

    Informations forums :
    Inscription : Janvier 2007
    Messages : 6 604
    Par défaut
    Bonjour,

    Citation Envoyé par StringBuilder Voir le message
    C'est plus un problème d'algo qu'autrechose... voir même de mathématique.

    Pour déterminer le nombre de chiffres, d'un point de vue algo, je vois donc comment faire :
    L'élégance y perdra surement, mais pourquoi ne pas faire la conversion et compter les digits tout simplement ?

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
                int a = 50;
                int digitCount = Convert.ToString(a, 8).Length;

  3. #3
    Expert confirmé
    Avatar de StringBuilder
    Homme Profil pro
    Chef de projets
    Inscrit en
    Février 2010
    Messages
    4 197
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Chef de projets
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2010
    Messages : 4 197
    Billets dans le blog
    1
    Par défaut
    Ben parce qu'en fait, c'est la fonction Log() qui permet de faire ce que je cherche, et c'est plus élégant

    Surtout, je cherche à changer de base, mais en utilisant d'autres chiffres que les chiffres conventionnels.

    Par exemple, utiliser la base 26 pour compter "alphabétiquement", c'est à dire :

    A, B, C, ... Z, AA, AB, AC, ...

    Et faire une conversion va me produire un résultat contenant des chiffres + les 16 premières lettres (à compter que .NET sache convertir en base 26).

    Et du coup, il faudra que je me coltine des replaces pour mettre les bons "chiffres".

    Mais le problème est résolu avec le code suivant :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    int charcount = 1;
    if (number > 0)
    {
       charcount = (int)Math.Floor(Math.Log(number, 26) + 1);
    }

  4. #4
    Expert confirmé
    Avatar de StringBuilder
    Homme Profil pro
    Chef de projets
    Inscrit en
    Février 2010
    Messages
    4 197
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Chef de projets
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2010
    Messages : 4 197
    Billets dans le blog
    1
    Par défaut
    Grmpf... Je me rends compte que c'est bien plus complexe que ça... La numérotation avec les lettres est bien plus qu'une base alternative, c'est du grand n'importe quoi inventé par un fou furieux :/

    En effet, pour que A < AA, il faut que A != 0
    Idem pour que Z < AA

    Donc on passe en base 27 et non 26 et mais le zéro n'existe pas !

    Car A != 0
    Mais AA = Z + 1 donc quand on arrive au dernier chiffre, si on l'incrémente, on passe directement à 1 et non 0 !

    En gros, autant il est facile de générer la liste à partir d'un nombre donné en incrémentant de 1 à la fois, autant pour savoir comment s'écrit 987564 en lettres "à la sauce Excel", je ne vois pas du tout comment faire sans être obligé de représenter tous les nombres de 1 à 987564

  5. #5
    Inactif  
    Homme Profil pro
    Chef de projet NTIC
    Inscrit en
    Janvier 2007
    Messages
    6 604
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 64
    Localisation : France

    Informations professionnelles :
    Activité : Chef de projet NTIC

    Informations forums :
    Inscription : Janvier 2007
    Messages : 6 604
    Par défaut
    C'est pas indiscret de te demander l'objectif fonctionnel ?

  6. #6
    Expert confirmé
    Avatar de StringBuilder
    Homme Profil pro
    Chef de projets
    Inscrit en
    Février 2010
    Messages
    4 197
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Chef de projets
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2010
    Messages : 4 197
    Billets dans le blog
    1
    Par défaut
    Aucun, passer le temps, pour le challenge*
    * rayer mention inutile

    Plus exactement, quelqu'un à posé une question à propos de "compter" de AP à CI.

    En répondant à sa question, et en voulant faire "mieux que chez Bertrand d'en face" je suis tombé sur cet écueil...

    J'imagine que ceux qui travaillent avec Excel sont confronté à ce problème, même si Excel sait aussi référencer ses colonnes par un numérique.

  7. #7
    Inactif  
    Homme Profil pro
    Chef de projet NTIC
    Inscrit en
    Janvier 2007
    Messages
    6 604
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 64
    Localisation : France

    Informations professionnelles :
    Activité : Chef de projet NTIC

    Informations forums :
    Inscription : Janvier 2007
    Messages : 6 604
    Par défaut
    Citation Envoyé par StringBuilder Voir le message
    J'imagine que ceux qui travaillent avec Excel sont confronté à ce problème, même si Excel sait aussi référencer ses colonnes par un numérique.
    De toute façon, Excel ne calcul pas avec ses numéros alpha de colonnes, il se contente de les dénombrer.

    Il n'y a jamais à faire (AB + CX) * (DZ/EJ) par exemple,, tout au plus AB + 10 ou AB - 10. C'est juste un système de numérotation, pas un système de calcul.

  8. #8
    Max
    Max est déconnecté
    Expert confirmé

    Avatar de Max
    Homme Profil pro
    Artisan développeur
    Inscrit en
    Mai 2007
    Messages
    2 954
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Pyrénées Atlantiques (Aquitaine)

    Informations professionnelles :
    Activité : Artisan développeur
    Secteur : Industrie

    Informations forums :
    Inscription : Mai 2007
    Messages : 2 954
    Par défaut
    Salut.

    Pour compter le nombre de chiffres d'une valeur N, tu peux utiliser log10(N) + 1, exemple :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    int testValue = 4000 * 100;
    int digitsNumber = (int)(Math.Log10(Math.Abs(testValue))) + 1;
    Console.WriteLine(digitsNumber);
    Merci à Sehnsucht qui m'a appris cette astuce !

    [EDIT]Bon en fait désolé, j'ai lu trop en diagonale et mon post est un peu HS [/EDIT]

  9. #9
    Expert confirmé
    Avatar de StringBuilder
    Homme Profil pro
    Chef de projets
    Inscrit en
    Février 2010
    Messages
    4 197
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Chef de projets
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2010
    Messages : 4 197
    Billets dans le blog
    1
    Par défaut
    Oui, mais se pose toujours le problème, lors d'un traitement, tu veux dire "vérifiez la valeur dans la cellule 146,45" c'est incompréhensible, alors que "vérifiez la valeur dans la cellule EP45" c'est tout de suite plus parlant pour l'utilisateur.

    Sauf que pour savoir que 146 = EP... Bah mise à part compter colonne par colonne, je ne trouve pas de solution :/

  10. #10
    Expert confirmé
    Avatar de StringBuilder
    Homme Profil pro
    Chef de projets
    Inscrit en
    Février 2010
    Messages
    4 197
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Chef de projets
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2010
    Messages : 4 197
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par _Max_ Voir le message
    Salut.

    Pour compter le nombre de chiffres d'une valeur N, tu peux utiliser log10(N) + 1, exemple :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    int testValue = 4000 * 100;
    int digitsNumber = (int)(Math.Log10(Math.Abs(testValue))) + 1;
    Console.WriteLine(digitsNumber);
    Merci à Sehnsucht qui m'a appris cette astuce !

    [EDIT]Bon en fait désolé, j'ai lu trop en diagonale et mon post est un peu HS [/EDIT]
    Oui sauf que dans mon cas, c'est Floor(Log(x, y)) + 1 avec y = base mais le problème n'est plus là

  11. #11
    Expert confirmé
    Avatar de StringBuilder
    Homme Profil pro
    Chef de projets
    Inscrit en
    Février 2010
    Messages
    4 197
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Chef de projets
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2010
    Messages : 4 197
    Billets dans le blog
    1
    Par défaut
    A défaut d'un bel algo, voici une solution basée sur l'énumération.

    J'utilise une classe statique afin de conserver en mémoire la liste, qui n'est pas très volumineuse, afin d'éviter de la reconstituer à chaque fois !

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
     
    using System;
    using System.Collections.Generic;
     
    namespace DigitToChar
    {
        class Program
        {
            static void Main(string[] args)
            {
                int n;
                string s;
     
                n = 146;
                s = "EP";
                Console.WriteLine("Le nombre {0} a pour représentation colonne Excel {1}", n, n.ToExcelColumn());
                Console.WriteLine("La colonne Excel {0} a pour indice {1}", s, s.FromExcelColumn());
                Console.WriteLine();
     
                n = 26;
                s = "Z";
                Console.WriteLine("Le nombre {0} a pour représentation colonne Excel {1}", n, n.ToExcelColumn());
                Console.WriteLine("La colonne Excel {0} a pour indice {1}", s, s.FromExcelColumn());
                Console.WriteLine();
     
                n = 27;
                s = "AA";
                Console.WriteLine("Le nombre {0} a pour représentation colonne Excel {1}", n, n.ToExcelColumn());
                Console.WriteLine("La colonne Excel {0} a pour indice {1}", s, s.FromExcelColumn());
                Console.WriteLine();
     
                n = 1;
                s = "A";
                Console.WriteLine("Le nombre {0} a pour représentation colonne Excel {1}", n, n.ToExcelColumn());
                Console.WriteLine("La colonne Excel {0} a pour indice {1}", s, s.FromExcelColumn());
                Console.WriteLine();
     
                n = 18278;
                s = "ZZZ";
                Console.WriteLine("Le nombre {0} a pour représentation colonne Excel {1}", n, n.ToExcelColumn());
                Console.WriteLine("La colonne Excel {0} a pour indice {1}", s, s.FromExcelColumn());
                Console.WriteLine();
     
                Console.WriteLine("Comptage de AP à PI");
                for (int i = "AP".FromExcelColumn(), nb = "PI".FromExcelColumn(); i <= nb; i++)
                {
                    Console.Write(i.ToExcelColumn());
                    Console.Write(' ');
                }
                Console.WriteLine();
     
                Console.ReadKey(true);
            }
        }
     
        public static class IntExtension
        {
            public static string ToExcelColumn(this int n)
            {
                if (n < 1)
                {
                    throw new Exception("Les colonnes Excel sont numérotées à partir de 1.");
                }
                if (n > DigitsToChars.chars.Count)
                {
                    throw new Exception(string.Format("Le programme ne sais pas compter au delà de {0} colonnes. Estimez-vous heureux, Excel est limité à 256 !", DigitsToChars.chars.Count));
                }
                return DigitsToChars.chars[n - 1];
            }
        }
     
        public static class StringExtension
        {
            public static int FromExcelColumn(this string s)
            {
                if (s.Length == 0 || s.Length > 3)
                {
                    throw new Exception("La chaîne doit faire entre 1 et 3 caractères.");
                }
     
                return DigitsToChars.chars.IndexOf(s) + 1;
            }
        }
     
        public static class DigitsToChars
        {
            public static List<string> chars;
     
            static DigitsToChars()
            {
                chars = new List<string>();
     
                for (int i = 0; i < 26; i++)
                {
                    chars.Add(string.Format("{0}", (char)(65 + i)));
                }
     
                for (int i = 0; i < 26; i++)
                {
                    for (int j = 0; j < 26; j++)
                    {
                        chars.Add(string.Format("{0}{1}", (char)(65 + i), (char)(65 + j)));
                    }
                }
     
                for (int i = 0; i < 26; i++)
                {
                    for (int j = 0; j < 26; j++)
                    {
                        for (int k = 0; k < 26; k++)
                        {
                            chars.Add(string.Format("{0}{1}{2}", (char)(65 + i), (char)(65 + j), (char)(65 + k)));
                        }
                    }
                }
            }
        }
    }
    Le nombre 146 a pour représentation colonne Excel EP
    La colonne Excel EP a pour indice 146

    Le nombre 26 a pour représentation colonne Excel Z
    La colonne Excel Z a pour indice 26

    Le nombre 27 a pour représentation colonne Excel AA
    La colonne Excel AA a pour indice 27

    Le nombre 1 a pour représentation colonne Excel A
    La colonne Excel A a pour indice 1

    Le nombre 18278 a pour représentation colonne Excel ZZZ
    La colonne Excel ZZZ a pour indice 18278

    Comptage de AP à PI
    AP AQ AR AS AT AU AV AW AX AY AZ BA BB BC BD BE BF BG BH BI BJ BK BL BM BN BO BP
    BQ BR BS BT BU BV BW BX BY BZ CA CB CC CD CE CF CG CH CI CJ CK CL CM CN CO CP C
    Q CR CS CT CU CV CW CX CY CZ DA DB DC DD DE DF DG DH DI DJ DK DL DM DN DO DP DQ
    DR DS DT DU DV DW DX DY DZ EA EB EC ED EE EF EG EH EI EJ EK EL EM EN EO EP EQ ER
    ES ET EU EV EW EX EY EZ FA FB FC FD FE FF FG FH FI FJ FK FL FM FN FO FP FQ FR F
    S FT FU FV FW FX FY FZ GA GB GC GD GE GF GG GH GI GJ GK GL GM GN GO GP GQ GR GS
    GT GU GV GW GX GY GZ HA HB HC HD HE HF HG HH HI HJ HK HL HM HN HO HP HQ HR HS HT
    HU HV HW HX HY HZ IA IB IC ID IE IF IG IH II IJ IK IL IM IN IO IP IQ IR IS IT I
    U IV IW IX IY IZ JA JB JC JD JE JF JG JH JI JJ JK JL JM JN JO JP JQ JR JS JT JU
    JV JW JX JY JZ KA KB KC KD KE KF KG KH KI KJ KK KL KM KN KO KP KQ KR KS KT KU KV
    KW KX KY KZ LA LB LC LD LE LF LG LH LI LJ LK LL LM LN LO LP LQ LR LS LT LU LV L
    W LX LY LZ MA MB MC MD ME MF MG MH MI MJ MK ML MM MN MO MP MQ MR MS MT MU MV MW
    MX MY MZ NA NB NC ND NE NF NG NH NI NJ NK NL NM NN NO NP NQ NR NS NT NU NV NW NX
    NY NZ OA OB OC OD OE OF OG OH OI OJ OK OL OM ON OO OP OQ OR OS OT OU OV OW OX O
    Y OZ PA PB PC PD PE PF PG PH PI

  12. #12
    Membre Expert Avatar de sisqo60
    Homme Profil pro
    Consultant informatique
    Inscrit en
    Février 2006
    Messages
    754
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Indre et Loire (Centre)

    Informations professionnelles :
    Activité : Consultant informatique

    Informations forums :
    Inscription : Février 2006
    Messages : 754
    Par défaut
    Bonjour,

    Les grands esprits se rencontrent, j'ai fait la même chose que toi tout à l'heure qui a découlé du même sujet . J'y crois pas il existe un gars aussi déjanté que moi!!!

    le code :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
            private void Afficher()
            {
                for (int i = 0; i < 1000; i++)
                {
                    Console.WriteLine(string.Format("{0} = {1}", i, ConvertToAlpha(i, 26)));
     
                }
            }
     
            private string ConvertToAlpha(int nbr, int basen)
            {
                int reste, quotient, diviseur;
                string convert;
                diviseur = basen;
                quotient = 1;
                convert = string.Empty;
     
                while (quotient != 0)
                {
                    quotient = nbr / diviseur;
                    reste = nbr % diviseur;
                    nbr = quotient;
     
     
                    convert = Convert.ToChar((reste + 'A')) + convert;
                }
     
                return convert;
            }
    J'ai pensé à généraliser, mais je me suis rendu compte comme toi que ce n'est pas tout à fait logique. C'est une question d'espace vectoriel (si mes souvenirs sont bon, ils datent oui je sais, mais si un étudient en maths ou une personne pour qui c'est toujours frais peut confirmer ou infirmer... ). j'ai pensé à faire une structure mais avec mais comme ça donne un espace vectoriel non commutatif (sans élément neutre tel que le zéro), ça peut pas marche (enfin si mes souvenirs sont toujours bons).

    Bon tournage de pouce

  13. #13
    Rédacteur
    Avatar de Nathanael Marchand
    Homme Profil pro
    Expert .Net So@t
    Inscrit en
    Octobre 2008
    Messages
    3 615
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Expert .Net So@t
    Secteur : Conseil

    Informations forums :
    Inscription : Octobre 2008
    Messages : 3 615
    Par défaut
    Je ne vois pas ou est le problème

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    void Main()
    {	
    	for(int i = 1; i < 110; i++)
    	{
    		var s = Convert(i);
    		String.Format("{0} = {1} = {2}", i, s, ConvertBack(s)).Dump();
    	}
    }
     
    static string Convert(int l)
    {
    	l = l - 1;
    	var r = String.Empty;
     
    	while(l >= 26)
    	{
    		r = r + ((char)('A' + (l / 26) - 1));
    		l = (l % 26);
    	}
     
    	r = r + ((char)('A' + (l % 26)));
     
    	return r;
    }
     
    static int ConvertBack(String s)
    {
    	return Enumerable.Range(0, s.Length)
    			.Select(e =>
    				new	{
    						M = (s.Length - e - 1) * 26,
    						C = (int)(s[e] - 'A') + 1
    					})
    			.Sum(e => Math.Max(e.M, 1) * e.C);
    }

  14. #14
    Expert confirmé
    Avatar de StringBuilder
    Homme Profil pro
    Chef de projets
    Inscrit en
    Février 2010
    Messages
    4 197
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Chef de projets
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2010
    Messages : 4 197
    Billets dans le blog
    1
    Par défaut
    Hmmm, ça me semble hyper compliqué ton truc (surtout la méthode decode, déjà que je suis pas familier de Linq, mais alors là, j'ai rien compris )

    En revanche, si je ne m'abuse, tu est limité à 1 ou 2 lettres, non ? Que se passe-t-il si tu veux compter jusqu'à 1000 ? (bon, ok, on sort du cadre Excel)

  15. #15
    Rédacteur
    Avatar de Nathanael Marchand
    Homme Profil pro
    Expert .Net So@t
    Inscrit en
    Octobre 2008
    Messages
    3 615
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Expert .Net So@t
    Secteur : Conseil

    Informations forums :
    Inscription : Octobre 2008
    Messages : 3 615
    Par défaut
    Version non LINQ:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     
    static int ConvertBack(String s)
    {
    	int r = 0;
    	int row = 0;
    	foreach (var letter in s)
    	{
    		r += Math.Max((s.Length - row - 1) * 26, 1) * ((int)(letter - 'A') + 1);
    		row++;
    	}
    	return r;
    }
    Bon effectivement, ca marche que jusqu'à 700 car après on passe sur 3 lettres.

  16. #16
    Expert confirmé
    Avatar de StringBuilder
    Homme Profil pro
    Chef de projets
    Inscrit en
    Février 2010
    Messages
    4 197
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Chef de projets
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2010
    Messages : 4 197
    Billets dans le blog
    1
    Par défaut
    Bon, ça m'a donné envie de me casser un peu plus la tête, et finalement j'ai réussi à trouver un algo "qui marche quel que soit le nombre de caractères" :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
     
        public static class StringExtension
        {
            public static string Reverse(this string s)
            {
                char[] chars = s.ToCharArray();
                Array.Reverse(chars);
                return new string(chars);
            }
        }
     
        public static class Method2
        {
            const string CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
     
            public static string Encode(int i)
            {
                StringBuilder sb = new StringBuilder();
     
                while (i > 0)
                {
                    sb.Append((char)('A' + ((i-- - 1) % 26)));
                    i /= 26;
                }
     
                return sb.ToString().Reverse();
            }
     
            public static int Decode(string s)
            {
                int ret = 0;
     
                s = s.Reverse();
     
                for (int i = 0, nb = s.Length; i < nb; i++)
                {
                    ret += (CHARS.IndexOf(s[i]) + 1) * (int)Math.Pow(26, i);
                }
                return ret;
            }
        }
    J'ai testé sur une plage allant de A à ZZZ et ça me donne le même résultat que la méthode énumérative.

    Etonnament (ou non) la méthode énumérative est BEAUCOUP plus lente que la méthode utilisant des calculs.
    C'est clairement dû à la méthode FromExcelColumn() qui semble particulièrement lente (la première fois que j'ai testé, je ne l'avais pas utilisée, et la tendance était inversée).

    J'ai généré 4 fois de suite les plages A à ZZZ.
    Méthode 1 est énumérative
    Méthode 2 est celle que je viens de donner

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     
    Méthode 1 : 18278 lignes (189224 caractères) calculées en 2681 millisecondes
    Méthode 2 : 18278 lignes (189224 caractères) calculées en 42 millisecondes
     
    Méthode 1 : 18278 lignes (189224 caractères) calculées en 2621 millisecondes
    Méthode 2 : 18278 lignes (189224 caractères) calculées en 41 millisecondes
     
    Méthode 1 : 18278 lignes (189224 caractères) calculées en 2609 millisecondes
    Méthode 2 : 18278 lignes (189224 caractères) calculées en 59 millisecondes
     
    Méthode 1 : 18278 lignes (189224 caractères) calculées en 2616 millisecondes
    Méthode 2 : 18278 lignes (189224 caractères) calculées en 39 millisecondes
    Le code complet de mon bidouillage du mercredi
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
     
    using System;
    using System.Collections.Generic;
    using System.Diagnostics;
    using System.Linq;
    using System.Text;
     
    namespace DigitToChar
    {
        class Program
        {
            static void Main(string[] args)
            {
                Method1();
                Method2();
                Method1();
                Method2();
                Method1();
                Method2();
                Method1();
                Method2();
                Console.ReadKey(true);
            }
     
            public static void Method1()
            {
                Stopwatch sw = new Stopwatch();
                sw.Start();
                int n = 0;
                StringBuilder sb = new StringBuilder();
                for (int i = "A".FromExcelColumn(), nb = "ZZZ".FromExcelColumn(); i <= nb; i++)
                {
                    sb.AppendFormat("{0} = {1}", i.ToExcelColumn(), i.ToExcelColumn().FromExcelColumn());
                    n++;
                    //Console.Write(i.ToExcelColumn());
                    //Console.Write(' ');
                }
                sw.Stop();
                Console.WriteLine(string.Format("Méthode 1 : {0} lignes ({1} caractères) calculées en {2} millisecondes", n, sb.Length, sw.ElapsedMilliseconds));
                Console.WriteLine();
            }
     
            public static void Method2()
            {
                Stopwatch sw = new Stopwatch();
                sw.Start();
                int n = 0;
                StringBuilder sb = new StringBuilder();
                for (int i = DigitToChar.Method2.Decode("A"), nb = DigitToChar.Method2.Decode("ZZZ"); i <= nb; i++)
                {
                    sb.AppendFormat("{0} = {1}", DigitToChar.Method2.Encode(i), DigitToChar.Method2.Decode(DigitToChar.Method2.Encode(i)));
                    n++;
                    //Console.Write(DigitToChar.Method2.Encode(i));
                    //Console.Write(' ');
                }
                sw.Stop();
                Console.WriteLine(string.Format("Méthode 2 : {0} lignes ({1} caractères) calculées en {2} millisecondes", n, sb.Length, sw.ElapsedMilliseconds));
                Console.WriteLine();
            }
        }
     
        public static class IntExtension
        {
            public static string ToExcelColumn(this int n)
            {
                if (n < 1)
                {
                    throw new Exception("Les colonnes Excel sont numérotées à partir de 1.");
                }
                if (n > DigitsToChars.chars.Count)
                {
                    throw new Exception(string.Format("Le programme ne sais pas compter au delà de {0} colonnes. Estimez-vous heureux, Excel est limité à 256 !", DigitsToChars.chars.Count));
                }
                return DigitsToChars.chars[n - 1];
            }
        }
     
        public static class StringExtension
        {
            public static int FromExcelColumn(this string s)
            {
                if (s.Length == 0 || s.Length > 3)
                {
                    throw new Exception("La chaîne doit faire entre 1 et 3 caractères.");
                }
     
                return DigitsToChars.chars.IndexOf(s) + 1;
            }
     
            public static string Reverse(this string s)
            {
                char[] chars = s.ToCharArray();
                Array.Reverse(chars);
                return new string(chars);
            }
        }
     
        public static class DigitsToChars
        {
            public static List<string> chars;
     
            static DigitsToChars()
            {
                chars = new List<string>();
     
                for (int i = 0; i < 26; i++)
                {
                    chars.Add(string.Format("{0}", (char)(65 + i)));
                }
     
                for (int i = 0; i < 26; i++)
                {
                    for (int j = 0; j < 26; j++)
                    {
                        chars.Add(string.Format("{0}{1}", (char)(65 + i), (char)(65 + j)));
                    }
                }
     
                for (int i = 0; i < 26; i++)
                {
                    for (int j = 0; j < 26; j++)
                    {
                        for (int k = 0; k < 26; k++)
                        {
                            chars.Add(string.Format("{0}{1}{2}", (char)(65 + i), (char)(65 + j), (char)(65 + k)));
                        }
                    }
                }
            }
        }
     
        public static class Method2
        {
            const string CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
     
            public static string Encode(int i)
            {
                StringBuilder sb = new StringBuilder();
     
                while (i > 0)
                {
                    sb.Append((char)('A' + ((i-- - 1) % 26)));
                    i /= 26;
                }
     
                return sb.ToString().Reverse();
            }
     
            public static int Decode(string s)
            {
                int ret = 0;
     
                s = s.Reverse();
     
                for (int i = 0, nb = s.Length; i < nb; i++)
                {
                    ret += (CHARS.IndexOf(s[i]) + 1) * (int)Math.Pow(26, i);
                }
                return ret;
            }
        }
    }
    PS : J'ai testé sur ma brouette à roulette qui n'est ni plus ni moins qu'un Goupil légèrement boosté (je suis étonné d'ailleurs de ne pas devoir booter sur une disquette). Les résultats sont certainement sans commune mesure avec ceux d'une ordinateur normal...

Discussions similaires

  1. Récuperer un nombre dans une chaine de caractère
    Par ColonelHati dans le forum C
    Réponses: 4
    Dernier message: 27/04/2005, 14h50
  2. Réponses: 5
    Dernier message: 15/04/2005, 14h22

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo