Genera il nome della colonna Excel dall'indice


21

Questo viene da un problema di vita reale. Lo abbiamo risolto, ovviamente, ma sembra che avrebbe potuto essere fatto meglio, che è una soluzione troppo lunga e rotonda. Tuttavia, nessuno dei miei colleghi può pensare a un modo più conciso di scriverlo. Quindi lo presento come code-golf.

L'obiettivo è convertire un numero intero non negativo in una stringa nello stesso modo in cui Excel presenta le intestazioni di colonna. Così:

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

Deve funzionare almeno fino a 16.383, ma anche oltre è accettabile (nessun punto bonus però). Non vedo l'ora che arrivi la soluzione C #, ma, come da tradizione del code-golf, qualsiasi vero linguaggio di programmazione è il benvenuto.


Sei sicuro che 16383 dovrebbe essere XFD? Cosa ottieni per 676 e 702?
Peter Taylor,

Bene, questo è ciò che Excel mostra e l'ho trovato sul web che ha 16384 colonne. Lo proverò domani con il nostro codice (noto per funzionare) (è in tarda ora proprio dove vivo).
Vilx-

Inoltre, test con Excel stesso rivela che 676 = ZA e 702 = AAA.
Vilx-

1
Il motivo per cui chiedo è che ho scritto un semplice codice base-26, ho ottenuto risultati che si adattano perfettamente al tuo, ma si sono rotti il ​​676 e il 702.
Peter Taylor,

1
Sì. Non è Base-26. Questo è il problema. ;)
Vilx

Risposte:



20

Excel Formula :), 36 caratteri

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

Uso:

enter image description here

Scusa, non ho resistito ...


Arghh! In realtà avevo pensato di vietarlo, ma ho dimenticato di menzionarlo nel post! : D Tuttavia, le formule di Excel non sono un linguaggio di programmazione (e sì, anche Excel VBA è off limits). : P
Vilx-

@ Vilx- Grazie a Dio qualcuno ha trovato una soluzione più breve. Non voglio entrare nella storia essendo l'unica persona che ha vinto una gara di golf usando le formule di Excel :)
Dr. belisarius,

Potrei ancora accettare la tua risposta. >: D
Vilx-

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

4
È possibile eliminare 2 byte sostituendo "1"con1
Taylor Scott il

9

Perl, 17 caratteri

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

L' ..operatore fa la stessa cosa dell'incremento automatico magico, ma senza la necessità della variabile e del ciclo temporanei. A meno che non strict subsrientri nell'ambito di applicazione, le parole chiave Ae XFDvengono interpretate come stringhe.

( Questa risposta è stata suggerita da un utente anonimo come modifica di una risposta esistente . Ho sentito che merita di essere una risposta separata e l'ho fatta una. Dal momento che non sarebbe giusto per me ottenere un rappresentante, " ve l'ho fatta Community Wiki. )


Dal momento che è la risposta più breve finora, immagino che meriti di essere contrassegnato come "accettato" fino a quando non viene trovata una soluzione più breve (probabilmente disponibile solo in JonSkeetScript): P Ironic.
Vilx-

1
Dal momento che la domanda è vaga su come vengono effettuati input e output, ciò consente effettivamente di abbreviarlo notevolmente. Ad esempio, se l'input è attivo $_e l'output è il valore dell'espressione, (A..XFD)[$_]risolve la sfida con solo 12 caratteri .
Ilmari Karonen,

Mi dispiace come dovrebbe essere eseguito? Con perl 5.18 non stampa nulla quando viene dato come argomento a -E.
Ed Avis,

@EdAvis: ti sta aspettando di digitare un numero. Oppure potresti inserire il numero in un file e farlo perl -E 'say[A..XFD]->[<>]' < number.txt. Oppure, nelle shell che lo supportano, basta dare l'input dalla riga di comando con perl -E 'say[A..XFD]->[<>]' <<< 123.
Ilmari Karonen,

1
Penso che questo possa essere ottimizzato persay+(A..XFD)[<>]
Konrad Borowski il

6

C, 53 caratteri

È come giocare a golf con un martello ...

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

Versione normale:

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

E l'uso è così:

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']:)[]))

Meno golf:

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

Spiegazione

Il sequencecombinatore di Haskell prende un elenco di azioni e le esegue, restituendo il risultato di ciascuna azione in un elenco. Per esempio:

sequence [getChar, getChar, getChar]

è equivalente a:

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

In Haskell, le azioni sono trattate come valori e sono incollate insieme usando >>=(legare) e le returnprimitive. Qualsiasi tipo può essere un '"azione" se implementa questi operatori con un'istanza Monad .

Per inciso, il tipo di elenco ha un'istanza monade. Per esempio:

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

Questo è uguale [(1,4),(1,5),(1,6),(2,4),(2,5),(2,6),(3,4),(3,5),(3,6)]. Nota come la comprensione dell'elenco sia sorprendentemente simile:

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

Poiché gli elenchi sono un tipo di "azione", possiamo utilizzarli sequencecon gli elenchi. Quanto sopra può essere espresso come:

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

Quindi, sequenceci dà combinazioni gratuite!

Pertanto, per creare l'elenco:

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

Devo solo creare liste per passare sequence

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

Quindi utilizzare concatMapentrambi per applicare sequenceagli elenchi e concatenare gli elenchi risultanti. Per coincidenza, concatMapè la =<<funzione per le liste, quindi la monade delle liste mi fa radere anche qui alcuni caratteri.


5

Perl, 26 caratteri

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

3

Rubino, 35 caratteri

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

Uso:

puts e[16383]   # XFD

Nota: esiste anche una versione più breve (30 caratteri) che utilizza la ricorsione.

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

Ma usando questa funzione potresti dover aumentare le dimensioni dello stack per grandi numeri a seconda del tuo interprete 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''

puoi rimuovere 2 parentesi tirando +chr(65+i%26)dentro e testando i>=0, salvandoti 1 personaggio :)
quasimodo

Puoi anche radere 4 caratteri usando f=lambda i:invece didef f(i):return
Strigoides il

in realtà non funziona bene con i numeri 37 e superiori. Ho dovuto aggiornare un po 'questo codice:f = lambda i: i >= 0 and f(math.floor(i / 26 - 1)) + chr(int(round(65 + i % 26))) or ''
user007 l'

2

Scala, 62 caratteri

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

Uso:

println(f(16383))

ritorna:

XFD

Puoi provarlo su Simply scala . Copia e incolla la funzione e usa f(some integer)per vedere il risultato.


Non è necessario ""+il elsecaso.
Peter Taylor,

2

Excel VBA, 31 byte

Funzione di finestra immediata VBE anonima che accetta input dalla cella [A1]e output nella finestra immediata di VBE

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

2

JavaScript (Node.js) , 50 byte

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

Provalo online!

Vedendo che molte persone hanno iniziato a rispondere anche a questo ho risposto.

Nota :

Questo è fondamentalmente una fregatura della risposta di @ kevinCruijssen in Java abbreviata grazie al fatto che questo è JS.


2

PHP, 30 byte

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

Esegui come pipe con `-nr 'o provalo online .


Sono abbastanza sicuro che questo non fa ciò che è richiesto. Dopo Zsarebbe andato [piuttosto che AA.
Vilx-

@ Vilx- Lo prendo come prova del fatto che non conosci molto PHP. Ho aggiunto un TiO; vedere di persona.
Tito,

Santo ... hai ragione! Conosco abbastanza bene PHP, ma è così pieno di cose strane, che è impossibile sapere tutto. Questa particolare stranezza mi ha gettato via. Ecco, ho un voto e le mie scuse!
Vilx-

1

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

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

La chiamata s(16383)tornerà XFC.


Benvenuti in PPCG! Puoi aggiungere una spiegazione per gli utenti che non hanno familiarità con VB?
AdmBorkBork,

1
@AdmBorkBork Non c'è molto da aggiungere alle risposte precedenti, solo un legame linguistico!
LS_ᴅᴇᴠ

Questo sembra fallire in tutti i casi in cui i>675 - s(676)=A@@(previsto YZ), s(677)=A@A(previsto ZA)
Taylor Scott,

1
@TaylorScott Hai ragione. Ci
sto

1
@TaylorScott corretto, +6 byte ... Grazie.
LS_ᴅᴇᴠ

1

Javascript, 147 byte

Ho avuto un problema simile. Questo è il golf della soluzione. Le colonne di Excel sono biiettive 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))}

Espanso, ad eccezione dell'uso di 1 indici:

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
È possibile aggiungere un collegamento TIO. A parte questo, un'ottima prima risposta. Benvenuto anche in PPCG.
Muhammad Salman

Anche rispondere a una domanda posta 7 anni fa non è davvero una grande idea.
Muhammad Salman,

Ok, nvm questo è sbagliato su così tanti livelli come non l'ho mai visto
Muhammad Salman

Volevo porre questa domanda ma era un duplicato. Non sono sicuro di cosa stai ricevendo su @MuhammadSalman
MattH,

Ti ricontatterò tra un minuto, benvenuto in PPCG. bella risposta. Si prega di notare che quando si scrive una risposta è necessario fornire un programma completo o una funzione
Muhammad Salman

1

Java, 57 byte (ricorsivo)

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

Provalo online.

Spiegazione:

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

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

Provalo online.

Spiegazione:

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

Ciao. Scusa ma ho rubato il tuo codice: qui . :)
Muhammad Salman

@MuhammadSalman Hehe, nessun problema. In realtà ho ricevuto il mio dalla risposta alla Scala . ;)
Kevin Cruijssen,

1

Forth (gforth) , 59 byte

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

Provalo online!

Spiegazione

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 byte

Risposta ricorsiva come molte risposte precedenti.

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

Provalo online!


1

Powershell, 68 byte

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

Versione alternativa ricorsiva, 68 byte:

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

Script di prova:

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

Produzione:

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

Nota: Powershell non fornisce un divoperatore.


0

Haskell, 48

Pensavo davvero che avrei potuto battere l'altra voce di Haskell, ma purtroppo ...

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

Sono certo che è possibile radere un paio di personaggi, ma non scrivo Haskell da quasi un anno, quindi sono abbastanza arrugginito.

Non è esattamente ciò che chiameresti elegante.


Non male! :) Ma Ha - dopo oltre 3 anni, ancora nessuna soluzione C #. : D
Vilx-

Haha, davvero. Ma una soluzione C # è banale da scrivere usando questo stesso metodo. string f(int n){return n<0?"":f(n/26-1)+(char)(n%26+65);}57 caratteri, quindi mi sentirei quasi male pubblicandolo come risposta.
Fors,

0

Jq 1.5 , 71 byte

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

Si aspetta input in N . per esempio

def N:16383;

Allargato:

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

Provalo online!



Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.