Generar nombre de columna de Excel a partir del índice


21

Este viene de un problema de la vida real. Lo resolvimos, por supuesto, pero sigue sintiendo que podría haberse hecho mejor, que es una solución demasiado larga y indirecta. Sin embargo, ninguno de mis colegas puede pensar en una forma más sucinta de escribirlo. Por eso lo presento como código-golf.

El objetivo es convertir un entero no negativo en una cadena de la misma manera que Excel presenta sus encabezados de columna. Así:

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

Tiene que funcionar al menos hasta 16.383, pero más allá también es aceptable (aunque no hay puntos de bonificación). Estoy ansioso por la solución C #, pero, según las tradiciones del código de golf, cualquier lenguaje de programación real es bienvenido.


¿Estás seguro de que 16383 debería ser XFD? ¿Qué obtienes para 676 y 702?
Peter Taylor

Bueno, eso es lo que muestra Excel, y encontré en la web que tiene 16384 columnas. Lo probaré mañana con nuestro código (se sabe que funciona) (es tarde en la noche en este momento donde vivo).
Vilx-

Además, las pruebas con Excel revelan que 676 = ZA y 702 = AAA.
Vilx-

1
La razón por la que pregunto es que escribí un código directo de base 26, obtuve resultados que se ajustan exactamente a los suyos, pero quebraron en 676 y 702.
Peter Taylor

1
Sip. No es Base-26. Ese es el problema. ;)
Vilx-

Respuestas:



20

Fórmula Excel :), 36 caracteres

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

Uso:

ingrese la descripción de la imagen aquí

Lo siento, no pude resistir ...


Arghh! En realidad había pensado en prohibir esto, ¡pero olvidé mencionarlo en la publicación! : D Aún así, las fórmulas de Excel no son un lenguaje de programación (y sí, Excel VBA también está fuera de los límites). : P
Vilx-

@ Vilx- Gracias a Dios a alguien se le ocurrió una solución más corta. No quiero entrar en la historia siendo la única persona que ganó un concurso de golf usando fórmulas Excel :)
Dr. belisarius

Todavía podría aceptar tu respuesta. >: D
Vilx-

3
<laughter type="evil">Muhahahahaha!</laughter>
Vilx-

44
Puede eliminar 2 bytes reemplazando "1"con1
Taylor Scott

9

Perl, 17 caracteres

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

El ..operador hace lo mismo que el incremento automático mágico, pero sin la necesidad de la variable temporal y el bucle. A menos que strict subsesté dentro del alcance, las palabras desnudas Ay XFDse interpretan como cadenas.

( Esta respuesta fue sugerida por un usuario anónimo como una edición de una respuesta existente . Sentí que merecía ser una respuesta separada, y la hice. Como no sería justo para mí obtener reputación de ella, yo ' lo he hecho Community Wiki. )


Como es la respuesta más corta hasta ahora, creo que merece ser marcada como "aceptada" hasta que se encuentre una solución más corta (probablemente solo disponible en JonSkeetScript): P Ironic.
Vilx-

1
Dado que la pregunta es vaga sobre cómo se realizan las entradas y salidas, eso realmente permite acortar esto considerablemente. Por ejemplo, si la entrada está adentro $_y la salida es el valor de la expresión, entonces (A..XFD)[$_]resuelve el desafío con solo 12 caracteres .
Ilmari Karonen

Lo siento, ¿cómo se debe ejecutar esto? Con perl 5.18 no imprime nada cuando se le da como argumento para -E.
Ed Avis

@EdAvis: está esperando que escribas un número. O podría poner el número en un archivo y hacer perl -E 'say[A..XFD]->[<>]' < number.txt. O, en los shells que lo soportan, simplemente ingrese la entrada en la línea de comando con perl -E 'say[A..XFD]->[<>]' <<< 123.
Ilmari Karonen

1
Creo que esto se puede optimizar parasay+(A..XFD)[<>]
Konrad Borowski el

6

C, 53 caracteres

Es como jugar al golf con un martillo ...

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

Versión normal:

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

Y el uso es así:

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

5

Haskell, 48

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

Menos golfizado:

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

Explicación

El sequencecombinador de Haskell toma una lista de acciones y las realiza, devolviendo el resultado de cada acción en una lista. Por ejemplo:

sequence [getChar, getChar, getChar]

es equivalente a:

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

En Haskell, las acciones se tratan como valores, y se unen usando el >>=(enlace) y las returnprimitivas. Cualquier tipo puede ser una "acción" si implementa estos operadores al tener una instancia de Monad .

Por cierto, el tipo de lista tiene una instancia de mónada. Por ejemplo:

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

Esto es igual [(1,4),(1,5),(1,6),(2,4),(2,5),(2,6),(3,4),(3,5),(3,6)]. Observe cómo la comprensión de la lista es sorprendentemente similar:

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

Como las listas son un tipo de "acción", podemos usarlas sequencecon listas. Lo anterior se puede expresar como:

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

Por lo tanto, sequencenos da combinaciones gratis!

Por lo tanto, para construir la lista:

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

Solo necesito crear listas para pasar a sequence

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

Luego use concatMappara aplicar ambos sequencea las listas y concatenar las listas resultantes. Casualmente, concatMapes la =<<función para las listas, por lo que la mónada de la lista me permite afeitar algunos caracteres aquí también.


5

Perl, 26 caracteres.

$x='A';map$x++,1..<>;say$x

3

Ruby, 35 caracteres.

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

Uso:

puts e[16383]   # XFD

Nota: También hay una versión más corta (30 caracteres) usando recursividad.

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

Pero al usar esta función, es posible que deba aumentar el tamaño de la pila para números grandes dependiendo de su intérprete de ruby.


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) }

3

Python 45 51

f=lambda i:i>=0and f(i/26-1)+chr(65+i%26)or''

puede quitar 2 paréntesis, tirando +chr(65+i%26)dentro y pruebas para i>=0, ahorrándole 1 carácter :)
Quasimodo

También podría afeitarse 4 caracteres usando en f=lambda i:lugar dedef f(i):return
Strigoides

en realidad eso no funciona bien para los números 37 y superiores. Tuve que actualizar este código un poco:f = lambda i: i >= 0 and f(math.floor(i / 26 - 1)) + chr(int(round(65 + i % 26))) or ''
user007

2

Scala, 62 caracteres

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

Uso:

println(f(16383))

devoluciones:

XFD

Puedes probar esto en Simplemente scala . Copie y pegue la función y úsela f(some integer)para ver el resultado.


No necesitas el ""+sobre el elsecaso.
Peter Taylor el

2

Excel VBA, 31 bytes

Función de ventana inmediata anónima de VBE que toma la entrada de la celda [A1]y las salidas a la ventana inmediata de VBE

?Replace([Address(1,A1,4)],1,"")

2

JavaScript (Node.js) , 50 bytes

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

Pruébalo en línea!

Al ver que mucha gente comenzó a responder esto, yo también respondí.

Nota :

Esto es básicamente una estafa de la respuesta de @ kevinCruijssen en Java acortada gracias a que esto es JS.


2

PHP, 30 bytes

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

Ejecutar como pipe con '-nr' o probarlo en línea .


Estoy bastante seguro de que esto no hace lo que se requiere. Después Ziría en [lugar de AA.
Vilx-

@ Vilx- Tomo eso como prueba de que no sabes mucho PHP. Agregué un TiO; ver por ti mismo.
Titus

Santo ... tienes razón! Conozco PHP bastante bien, pero está tan lleno de cosas raras que es imposible saberlo todo. Esta particular rareza me arrojó. ¡Aquí, ten un voto positivo y mis disculpas!
Vilx-

1

VBA / VB6 / VBScript (no Excel), 73 bytes

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

Las llamadas s(16383)volverán XFC.


Bienvenido a PPCG! ¿Puedes agregar una explicación para los usuarios que no están familiarizados con VB?
AdmBorkBork

1
@AdmBorkBork No hay mucho que agregar a las respuestas anteriores, ¡solo enlaza el idioma!
LS_ᴅᴇᴠ

Esto parece fallar en todos los casos donde i>675 - s(676)=A@@(esperado YZ), s(677)=A@A(esperado ZA)
Taylor Scott

1
@ TaylorScott Tienes razón. Trabajando en ello ...
LS_ᴅᴇᴠ

1
@TaylorScott Corregido, +6 bytes ... Gracias.
LS_ᴅᴇᴠ

1

Javascript, 147 bytes

Tuve un problema similar. Este es el golf de la solución. Las columnas de Excel son biyectivas 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))}

Ampliado, excepto que usa índices 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));
}

1
Puede agregar un enlace TIO. Aparte de eso, una gran primera respuesta. También bienvenido a PPCG.
Muhammad Salman

También responder una pregunta hecha hace 7 años no es realmente una gran idea.
Muhammad Salman

Ok, nvm esto está mal en tantos niveles, ¿cómo es que nunca vi esto
Muhammad Salman

Quería hacer esta pregunta pero era un duplicado. No estoy seguro de lo que está recibiendo en @MuhammadSalman
MattH

Me pondré en contacto con usted en un minuto. De todos modos, bienvenido a PPCG. buena respuesta. Tenga en cuenta que al escribir una respuesta debe proporcionar un programa completo o una función
Muhammad Salman,

1

Java, 57 bytes (recursivo)

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

Pruébalo en línea.

Explicación:

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 bytes (iterativo)

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

Pruébalo en línea.

Explicación:

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

Hola. Lo siento pero robé tu código: Aquí . :)
Muhammad Salman

@ Muhammad Salman Jeje, no hay problema. De hecho, obtuve el mío de la respuesta de Scala . ;)
Kevin Cruijssen

1

Adelante (adelante) , 59 bytes

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

Pruébalo en línea!

Explicación

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

1

R , 65 bytes

Respuesta recursiva al igual que muchas respuestas anteriores.

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

Pruébalo en línea!


1

Powershell, 68 bytes

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

Versión recursiva alternativa, 68 bytes:

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

Script de prueba:

$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"
}

Salida:

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

Nota: Powershell no proporciona un divoperador.


0

Haskell, 48

Realmente pensé que podría vencer a la otra entrada de Haskell, pero por desgracia ...

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

Estoy seguro de que es posible eliminar un par de personajes de esto, pero no he codificado en Haskell durante casi un año, así que estoy bastante oxidado.

No es exactamente lo que llamarías elegante.


¡No está mal! :) Pero Ja - después de más de 3 años, todavía no hay solución C #. :RE
Vilx-

Jaja, de hecho. Pero una solución C # es trivial para escribir usando este mismo método. string f(int n){return n<0?"":f(n/26-1)+(char)(n%26+65);}57 caracteres, así que casi me sentiría mal al publicarlo como respuesta.
Fors

0

Jq 1.5 , 71 bytes

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

Espera entrada en N. p.ej

def N:16383;

Expandido:

[                       # 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

Pruébalo en línea!



Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.