Generieren Sie den Namen der Excel-Spalte aus dem Index


21

Dieser kommt von einem realen Problem. Wir haben es natürlich gelöst, aber wir haben immer das Gefühl, es hätte besser gemacht werden können, dass es zu langwierig und umständlich ist. Allerdings kann sich keiner meiner Kollegen eine prägnantere Schreibweise vorstellen. Daher präsentiere ich es als Code-Golf.

Das Ziel ist es, eine nichtnegative Ganzzahl in eine Zeichenfolge zu konvertieren, so wie Excel die Spaltenüberschriften darstellt. Somit:

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

Es muss mindestens bis zu 16.383 funktionieren, aber darüber hinaus ist es auch akzeptabel (aber keine Bonuspunkte). Ich freue mich am meisten auf die C # -Lösung, aber gemäß den Traditionen von Code-Golf ist jede echte Programmiersprache willkommen.


Sind Sie sicher, dass 16383 XFD sein sollte? Was bekommen Sie für 676 und 702?
Peter Taylor

Genau das zeigt Excel, und ich habe im Web festgestellt, dass es 16384 Spalten hat. Ich werde es morgen mit unserem (für die Arbeit bekannten) Code testen (es ist spät in der Nacht, in der ich wohne).
Vilx 24.

Testen mit Excel selbst zeigt außerdem, dass 676 = ZA und 702 = AAA.
Vilx

1
Der Grund, den ich frage, ist, dass ich einen einfachen Base-26-Code geschrieben habe, Ergebnisse erzielt habe, die genau zu Ihnen passen, aber bei 676 und 702 gebrochen haben.
Peter Taylor,

1
Jep. Es ist nicht Base-26. Das ist das Problem. ;)
Vilx-

Antworten:



20

Excel Formula :), 36 Zeichen

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

Verwendung:

Bildbeschreibung hier eingeben

Entschuldigung, konnte nicht widerstehen ...


Arghh! Ich hatte tatsächlich daran gedacht, dies zu verbieten, aber vergessen, es in der Post zu erwähnen! : D Trotzdem sind Excel-Formeln keine Programmiersprache (und ja, Excel VBA ist auch tabu). : P
Vilx

@ Vilx- Gott sei Dank hat sich jemand eine kürzere Lösung ausgedacht. Ich möchte nicht in die Geschichte eingehen, als einzige Person, die einen Golfwettbewerb mit Excel-Formeln gewonnen hat :)
Dr. belisarius

Ich könnte immer noch Ihre Antwort akzeptieren. >: D
Vilx

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

4
Sie können durch Ersetzen von 2 Bytes fallen "1"mit1
Taylor Scott

9

Perl, 17 Zeichen

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

Der ..Operator macht dasselbe wie das magische automatische Inkrementieren, benötigt jedoch keine temporäre Variable und Schleife. Es sei denn , strict subsin Rahmen ist, die Barewords Aund XFDwerden als Strings interpretiert.

( Diese Antwort wurde vorgeschlagen , von einem anonymen Benutzer als Bearbeitung auf einer bestehenden Antwort . Ich fühlte es verdient eine gesonderte Antwort zu sein, und haben es zu einem gemacht. Da es nicht fair wäre für mich rep zu gewinnen aus, ich‘ habe es zum Community Wiki gemacht. )


Da es sich bisher um die kürzeste Antwort handelt, sollte sie meines Erachtens als "akzeptiert" markiert werden, bis eine kürzere Lösung gefunden wird (wahrscheinlich nur in JonSkeetScript verfügbar): P Ironic.
Vilx

1
Da die Frage, wie Input und Output erfolgen, vage ist, kann dies tatsächlich erheblich verkürzt werden. Wenn beispielsweise die Eingabe in $_und die Ausgabe der Wert des Ausdrucks ist, wird (A..XFD)[$_]die Herausforderung mit nur 12 Zeichen gelöst .
Ilmari Karonen

Entschuldigung, wie soll das laufen? In Perl 5.18 gibt es nichts aus, wenn es als Argument an -E übergeben wird.
Ed Avis

@EdAvis: Es wartet darauf, dass Sie eine Nummer eingeben. Oder Sie könnten die Nummer in eine Datei einfügen und tun perl -E 'say[A..XFD]->[<>]' < number.txt. Oder geben Sie in Shells, die dies unterstützen, einfach die Eingabe in der Befehlszeile mit ein perl -E 'say[A..XFD]->[<>]' <<< 123.
Ilmari Karonen

1
Ich denke, das kann optimiert werdensay+(A..XFD)[<>]
Konrad Borowski

6

C, 53 Zeichen

Es ist, als würde man mit einem Hammer Golf spielen ...

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

Normale Version:

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

Und die Verwendung ist wie folgt:

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

Weniger golfen:

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

Erläuterung

Der sequenceKombinator von Haskell führt eine Liste von Aktionen durch und gibt das Ergebnis jeder Aktion in einer Liste zurück. Beispielsweise:

sequence [getChar, getChar, getChar]

ist äquivalent zu:

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

In Haskell werden Aktionen wie Werte behandelt und unter Verwendung von >>=(Binden) und returnPrimitiven zusammengeklebt. Jeder Typ kann eine "Aktion" sein, wenn er diese Operatoren durch eine Monade implementiert Instanz .

Übrigens hat der Listentyp eine Monadeninstanz. Beispielsweise:

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

Das ist gleich [(1,4),(1,5),(1,6),(2,4),(2,5),(2,6),(3,4),(3,5),(3,6)]. Beachten Sie, dass das Listenverständnis auffällig ähnlich ist:

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

Da Listen eine Art "Aktion" sind, können wir sie sequencemit Listen verwenden. Das Obige kann ausgedrückt werden als:

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

Somit, sequence gibt uns Kombinationen kostenlos!

So erstellen Sie die Liste:

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

Ich muss nur Listen erstellen, an die ich übergebe sequence

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

Verwenden Sie dann, concatMapum beide sequenceauf die Listen anzuwenden und die resultierenden Listen zu verketten. Zufälligerweise concatMapist dies die =<<Funktion für Listen. Mit der Listenmonade kann ich auch hier einige Zeichen rasieren.


5

Perl, 26 Zeichen

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

3

Ruby, 35 Zeichen

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

Verwendung:

puts e[16383]   # XFD

Hinweis: Es gibt auch eine kürzere Version (30 Zeichen) mit Rekursion.

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

Bei Verwendung dieser Funktion müssen Sie möglicherweise die Stapelgröße für große Zahlen erhöhen, abhängig von Ihrem Ruby-Interpreter.


3

Groovy, 47 Jahre alt

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

Sie können 2 Klammern entfernen, indem Sie nach +chr(65+i%26)innen ziehen und testen i>=0, um 1 Zeichen zu speichern :)
quasimodo

Sie können auch 4 Zeichen aus , indem Sie rasieren , f=lambda i:anstattdef f(i):return
strigoides

Tatsächlich funktioniert das nicht gut für die Nummern 37 und höher. Ich musste diesen Code ein wenig aktualisieren:f = lambda i: i >= 0 and f(math.floor(i / 26 - 1)) + chr(int(round(65 + i % 26))) or ''
user007

2

Scala, 62 Zeichen

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

Verwendung:

println(f(16383))

kehrt zurück:

XFD

Sie können dies mit Simply Scala ausprobieren . Kopieren Sie die Funktion, fügen Sie sie ein und verwenden Sie f(some integer), um das Ergebnis anzuzeigen.


Sie brauchen das ""+auf dem elseFall nicht.
Peter Taylor

2

Excel VBA, 31 Bytes

Anonyme VBE-Direktfensterfunktion, die Eingaben von der Zelle [A1]und Ausgaben in das VBE-Direktfenster übernimmt

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


2

PHP, 30 Bytes

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

Führe es als Pipe mit -nr aus oder versuche es online .


Ich bin mir ziemlich sicher, dass dies nicht das tut, was erforderlich ist. Danach Zwürde es [eher gehen als AA.
Vilx

@ Vilx- Ich nehme das als Beweis dafür, dass du nicht viel PHP kennst. Ich habe ein TiO hinzugefügt; überzeugen Sie sich selbst.
Titus

Heilig ... du hast recht! Ich kenne PHP ziemlich gut, aber es ist so voll von seltsamen Dingen, dass es unmöglich ist, alles zu wissen. Diese besondere Kuriosität warf mich ab. Hier, habt eine Gegenstimme und ich entschuldige mich!
Vilx

1

VBA / VB6 / VBScript (nicht Excel), 73 Byte

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

Der Anruf s(16383)wird zurückgegeben XFC.


Willkommen bei PPCG! Können Sie eine Erklärung für Benutzer hinzufügen, die mit VB nicht vertraut sind?
AdmBorkBork

1
@AdmBorkBork Es gibt nicht viel zu früheren Antworten hinzuzufügen, nur Sprachbindung!
LS_ᴅᴇᴠ

Dies scheint in allen Fällen zu scheitern, in denen i>675 - s(676)=A@@(erwartet YZ), s(677)=A@A(erwartet ZA)
Taylor Scott

1
@ TaylorScott Du hast recht. Arbeiten daran ...
LS_ᴅᴇᴠ

1
@ TaylorScott Korrigiert, +6 Bytes ... Danke.
LS_ᴅᴇᴠ

1

Javascript, 147 Bytes

Ich hatte ein ähnliches Problem. Das ist der Golf der Lösung. Excel-Spalten sind bijektive Basis 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))}

Erweitert, außer bei Verwendung von 1-Indizes:

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
Sie könnten einen TIO-Link hinzufügen. Davon abgesehen eine großartige erste Antwort. Willkommen auch bei PPCG.
Muhammad Salman

Auch die Beantwortung einer vor 7 Jahren gestellten Frage ist keine wirklich gute Idee.
Muhammad Salman

Ok, nvm das ist auf so vielen Ebenen falsch, wie habe ich das jemals nicht gesehen
Muhammad Salman

Ich wollte diese Frage stellen, aber es war ein Duplikat. Ich bin mir nicht sicher, was du bei @ MuhammadSalman
MattH

Ich werde mich in Kürze bei Ihnen melden. Wie auch immer, willkommen bei PPCG. gute Antwort. Bitte beachten Sie, dass Sie beim Schreiben einer Antwort ein vollständiges Programm oder eine Funktion angeben müssen
Muhammad Salman,

1

Java, 57 Bytes (rekursiv)

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

Probieren Sie es online aus.

Erläuterung:

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 (iterativ)

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

Probieren Sie es online aus.

Erläuterung:

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

Hallo. Entschuldigung, aber ich habe Ihren Code gestohlen: Hier . :)
Muhammad Salman

@ Muhammad Salman Hehe, kein Problem. Ich habe meine tatsächlich von der Scala-Antwort erhalten . ;)
Kevin Cruijssen

1

Viertens (gviertens) , 59 Bytes

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

Probieren Sie es online!

Erläuterung

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

Powershell, 68 Bytes

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

Alternative rekursive Version, 68 Bytes:

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

Testskript:

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

Ausgabe:

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

Hinweis: Powershell bietet keinen divOperator.


0

Haskell, 48

Ich dachte wirklich, dass ich den anderen Haskell-Eintrag schlagen könnte, aber leider ...

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

Ich bin mir sicher, dass es möglich ist, ein paar Charaktere davon abzuhalten, aber ich habe fast ein Jahr lang nicht in Haskell codiert, also bin ich ziemlich rostig.

Es ist nicht genau das, was Sie als elegant bezeichnen würden.


Nicht schlecht! :) Aber Ha - nach mehr als 3 Jahren noch keine C # -Lösung. : D
Vilx

Haha, in der Tat. Es ist jedoch trivial, eine C # -Lösung mit derselben Methode zu schreiben. string f(int n){return n<0?"":f(n/26-1)+(char)(n%26+65);}57 Zeichen, also würde ich mich fast schlecht fühlen, wenn ich es als Antwort posten würde.
Fors

0

Jq 1,5 , 71 Bytes

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

Erwartet Eingaben in N. z.B

def N:16383;

Erweitert:

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

Probieren Sie es online!



Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.