Wygeneruj nazwę kolumny programu Excel z indeksu

21

Ten pochodzi z prawdziwego problemu z życia. Oczywiście rozwiązaliśmy to, ale nadal wydaje się, że można to zrobić lepiej, że jest to zbyt długie i okrągłe rozwiązanie. Jednak żaden z moich kolegów nie może wymyślić bardziej zwięzłego sposobu napisania tego. Dlatego przedstawiam to jako golf golfowy.

Celem jest przekonwertowanie nieujemnej liczby całkowitej na ciąg znaków w taki sam sposób, w jaki program Excel prezentuje nagłówki kolumn. A zatem:

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

Musi działać co najmniej do 16 383, ale poza tym jest również do przyjęcia (choć nie ma punktów bonusowych). Nie mogę się doczekać rozwiązania C #, ale zgodnie z tradycjami gry w golfa jest mile widziany każdy prawdziwy język programowania.

Vilx-
źródło
Czy na pewno 16383 powinno być XFD? Co dostajesz za 676 i 702?
Peter Taylor
Cóż, to pokazuje Excel i znalazłem w Internecie, że ma 16384 kolumny. Przetestuję to jutro z naszym (znanym z pracy) kodem (jest teraz późno w nocy, gdzie mieszkam).
Vilx-
Ponadto testy z samym Excelem wykazują, że 676 = ZA i 702 = AAA.
Vilx-
1
Pytam dlatego, że napisałem prosty kod 26, uzyskałem wyniki, które dokładnie pasują do twojego, ale zepsuły się na 676 i 702.
Peter Taylor
1
Tak. To nie jest Base-26. To jest problem. ;)
Vilx-

Odpowiedzi:

3

Perl 6 ,16 14 bajtów

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

Działa nawet poza XFD. Dzięki nieskończonym listom w Perlu 6 wykonanie tego nie trwa wiecznie (i pół).

Wypróbuj online!

Konrad Borowski
źródło
20

Formuła Excel :), 36 znaków

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

Stosowanie:

enter image description here

Przepraszam, nie mogłem się oprzeć ...

Dr Belizariusz
źródło
Aaaa! Myślałem o zakazaniu tego, ale zapomniałem o tym wspomnieć w poście! : D Mimo to formuły programu Excel nie są językiem programowania (i tak, program Excel VBA jest również niedostępny). : P
Vilx
@ Vilx- Dzięki Bogu ktoś wymyślił krótsze rozwiązanie. Nie chcę wchodzić w historię jako jedyna osoba, która wygrała zawody golfowe przy użyciu formuł Excela :)
Dr. Belisarius
Nadal mogę przyjąć twoją odpowiedź. >: D
Vilx
3
<laughter type="evil">Muhahahahaha!</laughter>
Vilx-
4
Można upuścić 2 bajty zastępując "1"z1
Taylor Scotta
9

Perl, 17 znaków

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

..Operator robi to samo, co magicznego automatycznego przyrostu, ale bez konieczności czasowego zmiennej i pętli. O ile nie strict subsjest w zakresie, na gołe słowa Ai XFDsą interpretowane jako ciągi.

( Ta odpowiedź była zasugerowana przez anonimowego użytkownika jako edycja istniejącej odpowiedzi . Czułem, że zasługuje na osobną odpowiedź, i uczyniłem ją jedną. Ponieważ nie byłoby fair, aby uzyskać z niej przedstawiciela, ja ” stworzyliśmy Wiki Wiki. )

Ilmari Karonen
źródło
Ponieważ jest to jak dotąd najkrótsza odpowiedź, myślę, że należy ją oznaczyć jako „zaakceptowaną”, dopóki nie zostanie znalezione krótsze rozwiązanie (prawdopodobnie dostępne tylko w JonSkeetScript): P Ironic.
Vilx-
1
Ponieważ pytanie, w jaki sposób dokonywane są dane wejściowe i wyjściowe, jest niejasne, pozwala to znacznie je skrócić. Na przykład, jeśli wejście jest w, $_a wyjście jest wartością wyrażenia, to (A..XFD)[$_]rozwiązuje wyzwanie tylko z 12 znakami .
Ilmari Karonen
Przepraszam, jak to powinno być uruchomione? W perlu 5.18 nic nie wypisuje, gdy podano jako argument -E.
Ed Avis,
@EdAvis: Czeka na Ciebie wpisanie numeru. Lub możesz umieścić numer w pliku i zrobić perl -E 'say[A..XFD]->[<>]' < number.txt. Lub, w powłokach, które go obsługują, po prostu podaj dane w wierszu poleceń za pomocą perl -E 'say[A..XFD]->[<>]' <<< 123.
Ilmari Karonen
1
Myślę, że można to zoptymalizowaćsay+(A..XFD)[<>]
Konrad Borowski
6

C, 53 znaki

To jak grać w golfa młotkiem ...

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

Wersja normalna:

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

A użycie jest takie:

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

Haskell, 48

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

Mniej golfa:

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

Wyjaśnienie

sequenceKombinator Haskella pobiera listę akcji i wykonuje je, zwracając wynik każdej akcji z listy. Na przykład:

sequence [getChar, getChar, getChar]

jest równa:

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

W Haskell akcje są traktowane jak wartości i są sklejane za pomocą >>=(bind) i returnprymitywów. Każdy typ może być „działaniem”, jeśli implementuje te operatory poprzez instancję Monady .

Nawiasem mówiąc, typ listy ma instancję monady. Na przykład:

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

To się równa [(1,4),(1,5),(1,6),(2,4),(2,5),(2,6),(3,4),(3,5),(3,6)]. Zwróć uwagę, jak rozumienie listy jest uderzająco podobne:

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

Ponieważ listy są rodzajem „akcji”, możemy ich używać sequencez listami. Powyższe można wyrazić jako:

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

W ten sposób sequencedaje nam połączona za darmo!

Tak więc, aby zbudować listę:

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

Muszę tylko zbudować listy, aby przejść sequence

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

Następnie użyj, concatMapaby zastosować oba sequencedo list i połączyć uzyskane listy. Przypadkowo concatMapjest to =<<funkcja list, więc monada listy pozwala mi również ogolić tutaj kilka znaków.

Joey Adams
źródło
5

Perl, 26 znaków

$x='A';map$x++,1..<>;say$x
Toto
źródło
3

Ruby, 35 znaków

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

Stosowanie:

puts e[16383]   # XFD

Uwaga: Istnieje również krótsza wersja (30 znaków) z rekurencją.

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

Ale korzystając z tej funkcji, być może będziesz musiał zwiększyć rozmiar stosu dla dużych liczb w zależności od interpretera ruby.

Howard
źródło
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
źródło
3

Python 45 51

f=lambda i:i>=0and f(i/26-1)+chr(65+i%26)or''
Daniel
źródło
możesz usunąć 2 nawiasy, wsuwając się do +chr(65+i%26)środka i testując i>=0, oszczędzając 1 znak :)
quasimodo
Możesz także ogolić 4 znaki, używając f=lambda i:zamiastdef f(i):return
Strigoides,
właściwie to nie działa dobrze dla liczb 37 i wyższych. Musiałem trochę zaktualizować ten kod:f = lambda i: i >= 0 and f(math.floor(i / 26 - 1)) + chr(int(round(65 + i % 26))) or ''
user007
2

Scala, 62 znaki

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

Stosowanie:

println(f(16383))

zwroty:

XFD

Możesz tego spróbować na Simply scala . Skopiuj i wklej funkcję i użyj, f(some integer)aby zobaczyć wynik.

Gareth
źródło
Nie potrzebujesz ""+tej elseskrzynki.
Peter Taylor
2

Excel VBA, 31 bajtów

Anonimowa funkcja bezpośredniego okna VBE, która przenosi dane wejściowe z komórki [A1]i dane wyjściowe do bezpośredniego okna VBE

?Replace([Address(1,A1,4)],1,"")
Taylor Scott
źródło
2

JavaScript (Node.js) , 50 bajtów

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

Wypróbuj online!

Widząc, że wiele osób zaczęło na nie odpowiadać, ja również odpowiedziałem.

Uwaga :

Jest to w zasadzie zdzierstwo odpowiedzi @ kevinCruijssen w Javie skróconej dzięki temu, że jest JS.

Muhammad Salman
źródło
2

PHP, 30 bajtów

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

Uruchom jako potok z `-nr 'lub wypróbuj online .

Tytus
źródło
Jestem prawie pewien, że to nie robi tego, co jest wymagane. Po Ztym [raczej by poszło AA.
Vilx-
@ Vilx- Przyjmuję to za dowód, że nie znasz dużo PHP. Dodałem TiO; Sam zobacz.
Tytus
Święty ... masz rację! Znam PHP dość dobrze, ale jest tak pełen dziwnych rzeczy, że nie można tego wszystkiego poznać. Ta szczególna dziwność mnie odrzuciła. Proszę, oddaj głos i przepraszam!
Vilx-
1

VBA / VB6 / VBScript (inny niż Excel), 73 bajty

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

Dzwonienie s(16383)powróci XFC.

LS_ᴅᴇᴠ
źródło
Witamy w PPCG! Czy możesz dodać wyjaśnienie dla użytkowników, którzy nie znają VB?
AdmBorkBork
1
@AdmBorkBork Niewiele do dodania do poprzednich odpowiedzi, wystarczy powiązanie językowe!
LS_ᴅᴇᴠ
To wydaje się nie działać we wszystkich przypadkach, w których i>675 - s(676)=A@@(oczekiwany YZ), s(677)=A@A(oczekiwany ZA)
Taylor Scott
1
@TaylorScott Masz rację. Pracuję nad tym ...
LS_ᴅᴇᴠ
1
@TaylorScott Poprawione, +6 bajtów ... Dzięki.
LS_ᴅᴇᴠ
1

JavaScript, 147 bajtów

Miałem podobny problem. To jest golf rozwiązania. Kolumny Excel są bijective 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))}

Rozszerzone, z wyjątkiem użycia 1-wskaźników:

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
źródło
1
Możesz dodać link TIO. Poza tym świetna pierwsza odpowiedź. Witamy również w PPCG.
Muhammad Salman
Odpowiedź na pytanie zadane 7 lat temu nie jest naprawdę świetnym pomysłem.
Muhammad Salman
Ok, nvm, to jest złe na tak wielu poziomach, jak ja tego nigdy nie widziałem
Muhammad Salman
Chciałem zadać to pytanie, ale było to duplikat. Nie jestem pewien, co otrzymujesz w @MuhammadSalman
MattH
Wrócę do ciebie za minutę. W każdym razie witamy w PPCG. niezła odpowiedź. Plz pamiętaj, że pisząc odpowiedź, musisz podać pełny program lub funkcję
Muhammad Salman
1

Java, 57 bajtów (rekurencyjne)

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

Wypróbuj online.

Wyjaśnienie:

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 bajty (iteracyjne)

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

Wypróbuj online.

Wyjaśnienie:

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
źródło
Cześć. Przepraszam, ale ukradłem twój kod: tutaj . :)
Muhammad Salman
@MuhammadSalman Hehe, nie ma problemu. Właściwie mam swoją odpowiedź Scali . ;)
Kevin Cruijssen
1

Dalej (gforth) , 59 bajtów

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

Wypróbuj online!

Wyjaśnienie

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
źródło
1

R , 65 bajtów

Odpowiedź rekurencyjna, tak jak wiele poprzednich odpowiedzi.

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

Wypróbuj online!

JayCe
źródło
1

PowerShell, 68 bajtów

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

Alternatywna wersja rekurencyjna, 68 bajtów:

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

Skrypt testowy:

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

Wynik:

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

Uwaga: PowerShell nie udostępnia divoperatora.

mazzy
źródło
0

Haskell, 48

Naprawdę myślałem, że uda mi się pokonać inne wejście do Haskell, ale niestety ...

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

Jestem pewien, że można zgolić kilka postaci, ale nie kodowałem w Haskell od prawie roku, więc jestem dość zardzewiały.

To nie jest dokładnie to, co nazwałbyś eleganckim.

Fors
źródło
Nie jest zły! :) Ale Ha - po ponad 3 latach wciąż nie ma rozwiązania C #. : D
Vilx
Haha, rzeczywiście. Ale rozwiązanie w języku C # jest łatwe do napisania przy użyciu tej samej metody. string f(int n){return n<0?"":f(n/26-1)+(char)(n%26+65);}57 znaków, więc prawie czułbym się źle, publikując go jako odpowiedź.
Fors
0

Jq 1,5 , 71 bajtów

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

Oczekuje wkładu N . na przykład

def N:16383;

Rozszerzony:

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

Wypróbuj online!

jq170727
źródło