Gere o nome da coluna do Excel a partir do índice

21

Este vem de um problema da vida real. Resolvemos isso, é claro, mas continua a parecer que poderia ter sido feito melhor, que é uma solução muito longa e indireta. No entanto, nenhum dos meus colegas pode pensar em uma maneira mais sucinta de escrevê-lo. Portanto, eu a apresento como código-golfe.

O objetivo é converter um número inteiro não negativo em uma seqüência de caracteres da mesma forma que o Excel apresenta seus cabeçalhos de coluna. Portanto:

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

Tem que funcionar pelo menos até 16.383, mas além disso também é aceitável (sem pontos de bônus). Estou ansioso pela solução C #, mas, de acordo com as tradições do code-golf, qualquer linguagem de programação real é bem-vinda.

Vilx-
fonte
Você tem certeza de que 16383 deve ser XFD? O que você ganha com 676 e 702?
Peter Taylor
Bem, é isso que o Excel mostra, e eu achei na web que ele tem 16384 colunas. Vou testá-lo amanhã com nosso código (conhecido por funcionar) (está tarde da noite no momento em que moro).
Vilx-
Além disso, o teste com o próprio Excel revela que 676 = ZA e 702 = AAA.
Vilx-
1
A razão que eu peço é que eu escrevi algum código simples base-26, obtive resultados que se ajustam a sua precisão, mas quebrou em 676 e 702.
Peter Taylor
1
Sim. Não é a Base-26. Esse é o problema. ;)
Vilx-

Respostas:

3

Perl 6 ,16 14 bytes

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

Funciona mesmo além do XFD. Graças às listas infinitas no Perl 6, isso não leva uma eternidade (e meia) para ser executado.

Experimente online!

Konrad Borowski
fonte
20

Fórmula do Excel :), 36 caracteres

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

Uso:

insira a descrição da imagem aqui

Desculpe, não pude resistir ...

Dr. belisarius
fonte
Arghh! Eu realmente pensei em proibir isso, mas esqueci de mencionar no post! : D Ainda assim, as fórmulas do Excel não são uma linguagem de programação (e sim, o Excel VBA também está fora dos limites). : P
Vilx-
@ Vilx- Graças a Deus alguém veio com uma solução mais curta. Não quero entrar na história, sendo a única pessoa que venceu um concurso de golfe usando as fórmulas do Excel :)
Dr. belisarius
Eu ainda posso aceitar sua resposta. >: D
Vilx-
3
<laughter type="evil">Muhahahahaha!</laughter>
Vilx-
4
Você pode eliminar 2 bytes substituindo "1"por1
Taylor Scott
9

Perl, 17 caracteres

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

O ..operador faz a mesma coisa que o incremento automático mágico, mas sem a necessidade da variável temporária e do loop. A menos que strict subsesteja no escopo, as palavras de barra Ae XFDsão interpretadas como seqüências de caracteres.

( Esta resposta foi sugerida por um usuário anônimo como uma edição para uma resposta existente . Eu senti que ela merece ser uma resposta separada e a criei. Uma vez que não seria justo eu obter representantes dela, eu " tornamos o Wiki da Comunidade. )

Ilmari Karonen
fonte
Como é a resposta mais curta até agora, acho que merece ser marcada como "aceita" até que uma solução mais curta seja encontrada (provavelmente disponível apenas no JonSkeetScript): P Ironic.
Vilx-
1
Como a pergunta é vaga sobre como as entradas e saídas são feitas, isso permite encurtar isso consideravelmente. Por exemplo, se a entrada está dentro $_e a saída é o valor da expressão, (A..XFD)[$_]resolve o desafio com apenas 12 caracteres .
Ilmari Karonen
Desculpe como isso deve ser executado? Com o perl 5.18, ele não imprime nada quando apresentado como argumento para -E.
Ed Avis
@ EdAvis: Está esperando você digitar um número. Ou você pode colocar o número em um arquivo e fazer perl -E 'say[A..XFD]->[<>]' < number.txt. Ou, nos shells que o suportam, basta fornecer a entrada na linha de comando com perl -E 'say[A..XFD]->[<>]' <<< 123.
Ilmari Karonen
1
Eu acho que isso pode ser otimizado parasay+(A..XFD)[<>]
Konrad Borowski
6

C, 53 caracteres

É como jogar golfe com um martelo ...

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

Versão normal:

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

E o uso é assim:

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

Haskell, 48

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

Menos golfe:

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

Explicação

O sequencecombinador de Haskell pega uma lista de ações e as executa, retornando o resultado de cada ação em uma lista. Por exemplo:

sequence [getChar, getChar, getChar]

é equivalente a:

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

No Haskell, as ações são tratadas como valores e coladas usando o >>=(bind) e o returnprimitivo. Qualquer tipo pode ser uma "ação" se implementar esses operadores tendo uma instância do Monad .

Aliás, o tipo de lista possui uma instância de mônada. Por exemplo:

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

Isso é igual [(1,4),(1,5),(1,6),(2,4),(2,5),(2,6),(3,4),(3,5),(3,6)]. Observe como a compreensão da lista é surpreendentemente semelhante:

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

Como listas são um tipo de "ação", podemos usar sequencecom listas. O acima pode ser expresso como:

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

Assim, sequencenos dá combinações de graça!

Assim, para construir a lista:

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

Eu só preciso criar listas para passar para sequence

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

Em seguida, use concatMappara aplicar sequence- se às listas e concatenar as listas resultantes. Coincidentemente, concatMapé a =<<função das listas; portanto, a mônada da lista também permite que eu raspe alguns caracteres aqui.

Joey Adams
fonte
5

Perl, 26 caracteres

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

Ruby, 35 caracteres

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

Uso:

puts e[16383]   # XFD

Nota: Também há uma versão mais curta (30 caracteres) usando recursão.

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

Mas, usando esta função, você pode ter que aumentar o tamanho da pilha para grandes números, dependendo do seu interpretador de ruby.

Howard
fonte
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
fonte
3

Python 45 51

f=lambda i:i>=0and f(i/26-1)+chr(65+i%26)or''
Daniel
fonte
você pode remover 2 parênteses puxando +chr(65+i%26)para dentro e testando para i>=0, poupando-lhe um caráter :)
Quasimodo
Você também pode raspar 4 caracteres off usando f=lambda i:, em vez dedef f(i):return
strigoides
na verdade, isso não funciona bem para os números 37 e acima. Eu tive que atualizar este código um pouco:f = lambda i: i >= 0 and f(math.floor(i / 26 - 1)) + chr(int(round(65 + i % 26))) or ''
user007 11/11
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))

retorna:

XFD

Você pode tentar isso no Simply scala . Copie e cole a função e use f(some integer)para ver o resultado.

Gareth
fonte
Você não precisa ""+do elsecaso.
Peter Taylor
2

Excel VBA, 31 bytes

Função de janela imediata VBE anônima que recebe entrada da célula [A1]e sai para a janela imediata VBE

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

JavaScript (Node.js) , 50 bytes

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

Experimente online!

Vendo que muitas pessoas começaram a responder a isso, eu também respondi.

Nota :

Isso é basicamente um roubo da resposta de @ kevinCruijssen em Java, encurtado graças ao fato de ser JS.

Muhammad Salman
fonte
2

PHP, 30 bytes

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

Execute como pipe com `-nr 'ou tente online .

Titus
fonte
Tenho certeza de que isso não faz o que é necessário. Depois Zque iria, em [vez de AA.
Vilx-
@ Vilx- Tomo isso como prova de que você não conhece muito PHP. Eu adicionei um TiO; Veja por si mesmo.
Titus
Santo ... você está certo! Eu sei muito bem o PHP, mas é tão cheio de coisas estranhas que é impossível saber tudo. Essa singularidade em particular me excitou. Aqui, tenha um voto positivo e minhas desculpas!
Vilx-
1

VBA / VB6 / VBScript (não Excel), 73 bytes

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

A chamada s(16383)retornará XFC.

LS_ᴅᴇᴠ
fonte
Bem-vindo ao PPCG! Você pode adicionar uma explicação para usuários não familiarizados com o VB?
AdmBorkBork 17/10
1
@AdmBorkBork Não há muito a acrescentar às respostas anteriores, apenas a ligação do idioma!
LS_ᴅᴇᴠ
Este parece falhar em todos os casos em que i>675 - s(676)=A@@(esperados YZ), s(677)=A@A(espera ZA)
Taylor Scott
1
@TaylorScott Você está certo. Trabalhando nisso ...
LS_ᴅᴇᴠ
1
@TaylorScott corrigido, +6 bytes ... Obrigado.
LS_ᴅᴇᴠ
1

Javascript, 147 bytes

Eu tive um problema parecido. Este é o golfe da solução. As colunas do Excel são bijetivas 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))}

Expandido, exceto usando í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));
}
MattH
fonte
1
Você pode adicionar um link TIO. Fora isso, uma ótima primeira resposta. Bem-vindo também ao PPCG.
Muhammad Salman
Também responder a uma pergunta feita há 7 anos não é realmente uma ótima idéia.
Muhammad Salman
Ok, NVM isso é errado em tantos níveis como é que eu já não vejo isso
Muhammad Salman
Eu queria fazer essa pergunta, mas era uma duplicata. Não tenho certeza do que você está recebendo no @MuhammadSalman
MattH
Entrarei em contato em breve. Seja bem-vindo ao PPCG. boa resposta. Observe que, ao escrever uma resposta, você deve fornecer um programa ou uma função completa
Muhammad Salman
1

Java, 57 bytes (recursivo)

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

Experimente online.

Explicação:

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

Experimente online.

Explicação:

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
fonte
Oi. Desculpe, mas roubei seu código: Aqui . :)
Muhammad Salman
@MuhammadSalman Hehe, não há problema. Na verdade, eu recebi o meu da resposta Scala . ;)
Kevin Cruijssen
1

Quarto (gforth) , 59 bytes

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

Experimente online!

Explicação

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
fonte
1

R , 65 bytes

Resposta recursiva, como muitas respostas anteriores.

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

Experimente online!

JayCe
fonte
1

Powershell, 68 bytes

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

Versão recursiva alternativa, 68 bytes:

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

Script de teste:

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

Saída:

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

Nota: O PowerShell não fornece um divoperador.

confuso
fonte
0

Haskell, 48

Eu realmente pensei que seria capaz de vencer a outra entrada Haskell, mas infelizmente ...

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

Estou certo de que é possível raspar alguns caracteres disso, mas não codigo em Haskell há quase um ano, por isso estou bastante enferrujado.

Não é exatamente o que você chamaria de elegante.

Para s
fonte
Não é ruim! :) Mas Ha - depois de mais de 3 anos, ainda não há solução C #. : D
Vilx-
Haha, de fato. Mas uma solução C # é trivial para escrever usando esse mesmo método. string f(int n){return n<0?"":f(n/26-1)+(char)(n%26+65);}57 caracteres, então eu quase me sentiria mal por postá-lo como resposta.
Fors
0

Jq 1.5 , 71 bytes

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

Espera entrada N. por exemplo

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

Experimente online!

jq170727
fonte