Générer un nom de colonne Excel à partir de l'index

21

Celui-ci vient d'un problème réel. Nous l'avons résolu, bien sûr, mais il semble toujours que cela aurait pu être mieux fait, que c'est une solution trop longue et détournée. Cependant, aucun de mes collègues ne peut penser à une manière plus succincte de l'écrire. Je le présente donc comme du code-golf.

Le but est de convertir un entier non négatif en une chaîne de la même manière qu'Excel présente ses en-têtes de colonne. Donc:

0 -> A
1 -> B
...
25 -> Z
26 -> AA
27 -> AB
...
51 -> AZ
52 -> BA
...
16,383 -> XFD

Il doit fonctionner au moins jusqu'à 16 383, mais au-delà est également acceptable (pas de points bonus cependant). J'attends le plus avec impatience la solution C #, mais, selon les traditions du code-golf, tout véritable langage de programmation est le bienvenu.

Vilx-
la source
Êtes-vous sûr que 16383 devrait être XFD? Qu'obtenez-vous pour 676 et 702?
Peter Taylor
Eh bien, c'est ce qu'Excel montre, et je l'ai trouvé sur le Web qu'il contient 16384 colonnes. Je vais le tester demain avec notre code (connu pour fonctionner) (c'est tard dans la nuit en ce moment où je vis).
Vilx
De plus, les tests avec Excel lui-même révèlent que 676 = ZA et 702 = AAA.
Vilx
1
La raison pour laquelle je demande, c'est que j'ai écrit un code simple en base 26, que j'ai obtenu des résultats qui correspondent exactement au vôtre, mais que je suis tombé en panne sur 676 et 702.
Peter Taylor
1
Ouaip. Ce n'est pas Base-26. C'est le problème. ;)
Vilx-

Réponses:

3

Perl 6 ,16 14 octets

{("A"..*)[$_]}

Fonctionne même au-delà de XFD. Grâce aux listes infinies de Perl 6, cela ne prend pas une éternité (et demie) à s'exécuter.

Essayez-le en ligne!

Konrad Borowski
la source
20

Formule Excel :), 36 caractères

=SUBSTITUTE(ADDRESS(1,A1,4),"1","")

Usage:

enter image description here

Désolé, je n'ai pas pu résister ...

Dr. belisarius
la source
Arghh! J'avais en fait pensé à interdire cela, mais j'ai oublié de le mentionner dans le post! : D Pourtant, les formules Excel ne sont pas un langage de programmation (et oui, Excel VBA est également interdit). : P
Vilx
@ Vilx- Dieu merci, quelqu'un a trouvé une solution plus courte. Je ne veux pas entrer dans l'histoire en étant la seule personne à avoir remporté un concours de golf en utilisant des formules Excel :)
Dr. belisarius
Je pourrais toujours accepter votre réponse. >: D
Vilx
3
<laughter type="evil">Muhahahahaha!</laughter>
Vilx
4
Vous pouvez supprimer 2 octets en remplaçant "1"par1
Taylor Scott
9

Perl, 17 caractères

say[A..XFD]->[<>]

L' ..opérateur fait la même chose que l'auto-incrémentation magique, mais sans avoir besoin de la variable temporaire et de la boucle. Sauf si strict subsc'est dans la portée, les mots nus Aet XFDsont interprétés comme des chaînes.

( Cette réponse a été suggérée par un utilisateur anonyme en tant que modification d' une réponse existante . Je pensais qu'elle méritait d'être une réponse distincte, et je l'ai faite. Puisqu'il ne serait pas juste pour moi d'en gagner la réputation, je ' ve l'ont fait Wiki communautaire. )

Ilmari Karonen
la source
Comme c'est la réponse la plus courte jusqu'à présent, je suppose qu'elle mérite d'être marquée comme "acceptée" jusqu'à ce qu'une solution plus courte soit trouvée (probablement uniquement disponible dans JonSkeetScript): P Ironic.
Vilx
1
Étant donné que la question est vague sur la façon dont les entrées et les sorties sont effectuées, cela permet en fait de raccourcir considérablement cela. Par exemple, si l'entrée est entrée $_et que la sortie est la valeur de l'expression, (A..XFD)[$_]le problème est résolu avec seulement 12 caractères .
Ilmari Karonen du
Désolé, comment cela devrait-il être exécuté? Avec perl 5.18, il n'affiche rien lorsqu'il est donné comme argument à -E.
Ed Avis
@EdAvis: Il vous attend pour taper un nombre. Ou vous pouvez mettre le numéro dans un fichier et faire perl -E 'say[A..XFD]->[<>]' < number.txt. Ou, dans les shells qui le supportent, donnez simplement l'entrée sur la ligne de commande avec perl -E 'say[A..XFD]->[<>]' <<< 123.
Ilmari Karonen
1
Je pense que cela peut être optimisé poursay+(A..XFD)[<>]
Konrad Borowski
6

C, 53 caractères

C'est comme jouer au golf avec un marteau ...

char b[4],*p=b+3;f(i){i<0||(*--p=i%26+65,f(i/26-1));}

Version normale:

char b[4];
char *p = b+3;
void f(int i) {
    if (i >= 0) {
        --p;
        *p = i%26 + 65;
        f(i/26-1);
    }
}

Et l'usage est comme ça:

int main(int argc, char *argv[])
{
    f(atoi(argv[1]));
    printf("%s\n", p);
    return 0;
}
Alexander Bakulin
la source
5

Haskell, 48

f=(!!)(sequence=<<(tail$iterate(['A'..'Z']:)[]))

Moins golfé:

f n = (concatMap sequence $ tail $ iterate (['A'..'Z'] :) []) !! n

Explication

Le sequencecombinateur de Haskell prend une liste d'actions et les exécute, renvoyant le résultat de chaque action dans une liste. Par exemple:

sequence [getChar, getChar, getChar]

est équivalent à:

do
    a <- getChar
    b <- getChar
    c <- getChar
    return [a,b,c]

Dans Haskell, les actions sont traitées comme des valeurs et sont collées ensemble à l'aide de >>=(bind) et des returnprimitives. Tout type peut être une "action" s'il implémente ces opérateurs en ayant une instance Monad .

Par ailleurs, le type de liste a une instance de monade. Par exemple:

do
    a <- [1,2,3]
    b <- [4,5,6]
    return (a,b)

C'est égal [(1,4),(1,5),(1,6),(2,4),(2,5),(2,6),(3,4),(3,5),(3,6)]. Remarquez comment la compréhension de la liste est étonnamment similaire:

[(a,b) | a <- [1,2,3], b <- [4,5,6]]

Les listes étant un type "d'action", nous pouvons les utiliser sequenceavec des listes. Ce qui précède peut être exprimé comme suit:

sequence [[1,2,3],[4,5,6]]

Ainsi, sequencenous donne des combinaisons gratuitement!

Ainsi, pour construire la liste:

["A","B"..."Z","AA","AB"]

J'ai juste besoin de construire des listes pour passer à sequence

[['A'..'Z'],['A'..'Z','A'..'Z'],...]

Ensuite, utilisez concatMappour appliquer les deux aux sequencelistes et concaténer les listes résultantes. Par coïncidence, concatMapc'est la =<<fonction pour les listes, donc la monade de liste me permet de raser quelques caractères ici aussi.

Joey Adams
la source
5

Perl, 26 caractères

$x='A';map$x++,1..<>;say$x
Toto
la source
3

Ruby, 35 caractères

e=->n{a=?A;n.times{a.next!};a}

Usage:

puts e[16383]   # XFD

Remarque: Il existe également une version plus courte (30 caractères) utilisant la récursivité.

    e=->n{n<1??A:e[n-1].next}

Mais en utilisant cette fonction, vous devrez peut-être augmenter la taille de la pile pour les grands nombres en fonction de votre interprète ruby.

Howard
la source
3

Groovy, 47

m={it<0?'':m(((int)it/26)-1)+('A'..'Z')[it%26]}

[0:'A',1:'B',25:'Z',
        26:'AA',
        27:'AB',
        51:'AZ',
        52:'BA',
        16383:'XFD'].collect {k,v-> assert v == m(k);m(k) }
Armand
la source
3

Python 45 51

f=lambda i:i>=0and f(i/26-1)+chr(65+i%26)or''
Daniel
la source
vous pouvez supprimer 2 parenthèses en tirant +chr(65+i%26)à l' intérieur et en testant i>=0, vous économisant 1 caractère :)
quasimodo
Vous pouvez également raser 4 personnages en utilisant f=lambda i:plutôt quedef f(i):return
Strigoides
en fait, cela ne fonctionne pas bien pour les numéros 37 et supérieurs. J'ai dû mettre à jour un peu ce code:f = lambda i: i >= 0 and f(math.floor(i / 26 - 1)) + chr(int(round(65 + i % 26))) or ''
user007
2

Scala, 62 caractères

def f(i:Int):String=if(i<0)""else f((i/26)-1)+(i%26+65).toChar

Usage:

println(f(16383))

Retour:

XFD

Vous pouvez l'essayer sur Simply scala . Copiez et collez la fonction et utilisez f(some integer)pour voir le résultat.

Gareth
la source
Vous n'en avez pas besoin ""+sur le elseboîtier.
Peter Taylor
2

Excel VBA, 31 octets

Fonction de fenêtre immédiate VBE anonyme qui prend les entrées de la cellule [A1]et les sorties vers la fenêtre immédiate VBE

?Replace([Address(1,A1,4)],1,"")
Taylor Scott
la source
2

JavaScript (Node.js) , 50 octets

f=_=>_<0?'':f(_/26-1)+String.fromCharCode(_%26+65)

Essayez-le en ligne!

Voyant que beaucoup de gens ont commencé à répondre à cela, j'ai répondu aussi.

Remarque :

Il s'agit essentiellement d'une arnaque de la réponse de @ kevinCruijssen en Java raccourcie grâce à JS.

Muhammad Salman
la source
2

PHP, 30 octets

for($c=A;$argn--;)$c++;echo$c;

Exécutez en tant que pipe avec `-nr 'ou essayez-le en ligne .

Titus
la source
Je suis sûr que cela ne fait pas ce qui est requis. Après Zça irait [plutôt que AA.
Vilx-
@ Vilx - Je prends cela comme une preuve que vous ne connaissez pas beaucoup PHP. J'ai ajouté un TiO; voir par vous-même.
Titus
Saint ... tu as raison! Je connais assez bien PHP, mais il est tellement plein de trucs bizarres, qu'il est impossible de tout savoir. Cette bizarrerie particulière m'a bouleversé. Ici, ayez un vote positif et mes excuses!
Vilx
1

VBA / VB6 / VBScript (non Excel), 73 octets

Function s(i):While i:i=i-1:s=Chr(i Mod 26+65)&s:i=i\26:Wend:End Function

L'appel s(16383)reviendra XFC.

LS_ᴅᴇᴠ
la source
Bienvenue chez PPCG! Pouvez-vous ajouter une explication pour les utilisateurs peu familiers avec VB?
AdmBorkBork
1
@AdmBorkBork Pas grand chose à ajouter aux réponses précédentes, il suffit de lier la langue!
LS_ᴅᴇᴠ
Cela semble échouer dans tous les cas où i>675 - s(676)=A@@(attenduYZ ), s(677)=A@A(attendu ZA)
Taylor Scott
1
@TaylorScott Vous avez raison.
J'y
1
@TaylorScott corrigé, +6 octets ... Merci.
LS_ᴅᴇᴠ
1

Javascript, 147 octets

J'avais un problème similaire. C'est le golf de la solution. Les colonnes Excel sont bijectives base-26 .

n=>{f=Math.floor;m=Math.max;x=m(0,f((n-24)/676));y=m(0,f(n/26-x*26));return String.fromCharCode(...[x,y,n+1-x*676-y*26].filter(d=>d).map(d=>d+64))}

Développé, sauf en utilisant des indices 1:

function getColName(colNum){ // example: 16384 => "XFD"
    let mostSig = Math.max(0, Math.floor((colNum - 26 - 1)/26**2));
    let midSig = Math.max(0, Math.floor((colNum - mostSig*26**2 - 1)/26));
    let leastSig = colNum - mostSig*26**2 - midSig*26;

    return String.fromCharCode(...[mostSig,midSig,leastSig].filter(d=>d).map(d=>d+64));
}
MattH
la source
1
Vous pouvez ajouter un lien TIO. A part cela, une excellente première réponse. Bienvenue également à PPCG.
Muhammad Salman,
Répondre à une question posée il y a 7 ans n'est pas vraiment une bonne idée.
Muhammad Salman,
Ok, nvm c'est faux à tellement de niveaux comment n'ai-je jamais vu ça
Muhammad Salman
Je voulais poser cette question mais c'était un doublon. Je ne sais pas ce que vous obtenez à @MuhammadSalman
MattH
Je vous répondrai dans une minute, bienvenue à PPCG. Bonne réponse. Veuillez noter que lorsque vous écrivez une réponse, vous devez fournir un programme complet ou une fonction
Muhammad Salman
1

Java, 57 octets (récursif)

String f(int n){return n<0?"":f(n/26-1)+(char)(n%26+65);}

Essayez-le en ligne.

Explication:

String f(int n){        // Recursive method with integer parameter and String return-type
  return n<0?           //  If `n` is negative:
    ""                  //   Return an empty String
   :                    //  Else:
    f(n/26-1)           //   Recursive call with `n` integer-divided by 26, minus 1
    +(char)(n%26+65);}  //   And append `n%26+65` as character

Java 10, 62 octets (itératif)

n->{var r="";for(;n>=0;n=n/26-1)r=(char)(n%26+65)+r;return r;}

Essayez-le en ligne.

Explication:

n->{                      // Method with integer parameter and String return-type
  var r="";               //  Result-String, starting empty
  for(;n>=0;              //  Loop as long as `n` is not negative
      n=n/26-1)           //    After every iteration: divide `n` by 26, and subtract 1
    r=(char)(n%26+65)+r;  //   Prepend `n%26+65` as character to the result-String
  return r;}              //  Return the result-String
Kevin Cruijssen
la source
Salut. Désolé mais j'ai volé votre code: ici . :)
Muhammad Salman
@MuhammadSalman Hehe, pas de problème. J'ai en fait obtenu le mien de la réponse Scala . ;)
Kevin Cruijssen
1

Forth (gforth) , 59 octets

: f dup 0< if drop else 26 /mod 1- recurse 65 + emit then ;

Essayez-le en ligne!

Explication

dup 0<            \ duplicate the top of the stack and check if negative
if drop           \ if negative, drop the top of the stack
else              \ otherwise
   26 /mod        \ divide by 26 and get the quotient and remainder
   1- recurse     \ subtract one from quotient and recurse on result
   65 + emit      \ add 65 to remainder and output ascii char
then              \ exit if statement
reffu
la source
1

R , 65 octets

Réponse récursive comme le sont de nombreuses réponses précédentes.

function(n,u=LETTERS[n%%26+1])"if"(n<=25,u,paste0(g(n%/%26-1),u))

Essayez-le en ligne!

JayCe
la source
1

Powershell, 68 octets

param($n)for(;$n-ge0;$n=($n-$r)/26-1){$s=[char](($r=$n%26)+65)+$s}$s

Version récursive alternative, 68 octets:

filter g{if($_-ge0){(($_-($r=$_%26))/26-1|f)+[char]($r+65)}else{''}}

Script de test:

$f = {

param($n)for(;$n-ge0;$n=($n-$r)/26-1){$s=[char](($r=$n%26)+65)+$s}$s

}

filter g{if($_-ge0){(($_-($r=$_%26))/26-1|f)+[char]($r+65)}else{''}}


@(
    ,(0 , "A")
    ,(1 , "B")
    ,(25 , "Z")
    ,(26 , "AA")
    ,(27 , "AB")
    ,(51 , "AZ")
    ,(52 , "BA")
    ,(676 , "ZA")
    ,(702 , "AAA")
    ,(16383 , "XFD")
) | % {
    $n, $expected = $_
    $result = &$f $n
    # $result = $n|g      # Alternative
    "$($result-eq$expected): $result"
}

Production:

True: A
True: B
True: Z
True: AA
True: AB
True: AZ
True: BA
True: ZA
True: AAA
True: XFD

Remarque: Powershell ne fournit pas d' divopérateur.

mazzy
la source
0

Haskell, 48

Je pensais vraiment que je pourrais battre l'autre entrée de Haskell, mais hélas ...

f(-1)=""
f n=f(div n 26-1)++[toEnum$mod n 26+65]

Je suis certain qu'il est possible de raser quelques personnages, mais je n'ai pas codé en Haskell depuis près d'un an, donc je suis assez rouillé.

Ce n'est pas exactement ce que vous appelleriez élégant.

Fors
la source
Pas mal! :) Mais Ha - après plus de 3 ans, toujours pas de solution C #. : D
Vilx
Haha, en effet. Mais une solution C # est triviale à écrire en utilisant cette même méthode. string f(int n){return n<0?"":f(n/26-1)+(char)(n%26+65);}57 caractères, donc je me sentirais presque mal en le postant comme réponse.
Fors
0

Jq 1,5 , 71 octets

[range(1;4)as$l|[65+range(26)]|implode/""|combinations($l)]|map(add)[N]

Attend une entrée N. par exemple

def N:16383;

Étendu:

[                       # create array with
   range(1;4) as $l     #  for each length 1,2,3
 | [65+range(26)]       #   list of ordinal values A-Z
 | implode/""           #   converted to list of strings ["A", "B", ...]
 | combinations($l)     #   generate combinations of length $l
]
| map(add)[N]           # return specified element as a string

Essayez-le en ligne!

jq170727
la source