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.


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:



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 ...


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


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

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.


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: 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.


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''

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.


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,"")

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.


2

PHP, 30 bytes

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

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


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.


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

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

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

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!


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.


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.


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!



Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.