Создать имя столбца Excel из индекса


21

Это происходит из реальной жизни. Конечно, мы решили это, но у нас остается ощущение, что это можно было бы сделать лучше, что это слишком длинное и обходное решение. Однако ни один из моих коллег не может придумать более сжатый способ его написания. Поэтому я представляю это как код-гольф.

Цель состоит в том, чтобы преобразовать неотрицательное целое число в строку так же, как Excel представляет заголовки столбцов. Таким образом:

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

Он должен работать как минимум до 16383, но и за пределами приемлемо (хотя никаких бонусных баллов). Я с нетерпением жду решения C #, но, согласно традициям код-гольфа, любой настоящий язык программирования приветствуется.


Вы уверены, что 16383 должен быть XFD? Что вы получаете за 676 и 702?
Питер Тейлор

Ну, это то, что показывает Excel, и я обнаружил в Интернете, что он имеет 16384 столбца. Я проверю это завтра с нашим (известным по работе) кодом (сейчас поздно ночью, где я живу).
Vilx

Кроме того, тестирование с помощью Excel показывает, что 676 = ZA и 702 = AAA.
Vilx

1
Причина, по которой я спрашиваю, состоит в том, что я написал некоторый простой код base-26, получил результаты, которые точно соответствуют вашим, но разбились на 676 и 702.
Питер Тейлор

1
Ага. Это не Base-26. Это проблема. ;)
Vilx-

Ответы:



20

Excel Formula :), 36 символов

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

Использование:

введите описание изображения здесь

Извините, не удержался ...


Arghh! Я действительно думал о запрете этого, но забыл упомянуть об этом в посте! : D Тем не менее, формулы Excel не являются языком программирования (и да, Excel VBA тоже запрещен). : P
Vilx

@ Vilx - Слава Богу, кто-то придумал более короткое решение. Я не хочу входить в историю, потому что я единственный, кто выиграл соревнование по гольфу, используя формулы Excel :)
Доктор Белизариус

Я все еще могу принять ваш ответ. >: D
Vilx

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

4
Вы можете сбросить 2 байта, заменив "1"на1
Тейлор Скотт

9

Perl, 17 символов

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

..Оператор делает то же самое, что и волшебное автоприращение, но без необходимости временных переменного и петли. Если только strict subsв области видимости, голые слова Aи XFDинтерпретируются как строки.

( Этот ответ был предложен анонимным пользователем в качестве правки к существующему ответу . Я чувствовал, что он заслуживает того, чтобы быть отдельным ответом, и сделал его одним. Поскольку было бы несправедливо получить от него повторение, я ' Мы сделали это Сообщество Wiki. )


Поскольку это самый короткий ответ на данный момент, я думаю, он заслуживает того, чтобы его пометили как «принятый», пока не будет найдено более короткое решение (возможно, доступное только в JonSkeetScript): P Ironic.
Vilx-

1
Поскольку вопрос о том, как осуществляется ввод и вывод, является неопределенным, это фактически позволяет значительно сократить это. Например, если для входных данных задано значение input, $_а для выходных данных выбрано значение выражения, тогда (A..XFD)[$_]задача решается только с 12 символами .
Ильмари Каронен

Извините, как это должно быть запущено? С perl 5.18 он ничего не печатает, если указан как аргумент -E.
Эд Авис

@EdAvis: он ждет, когда вы наберете номер. Или вы можете поместить номер в файл и сделать perl -E 'say[A..XFD]->[<>]' < number.txt. Или в оболочках, которые его поддерживают, просто введите данные в командной строке с помощью perl -E 'say[A..XFD]->[<>]' <<< 123.
Илмари Каронен

1
Я думаю, что это может быть оптимизировано дляsay+(A..XFD)[<>]
Конрад Боровски

6

C, 53 символа

Это как играть в гольф с молотком ...

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

Нормальная версия:

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

И использование так:

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

5

Хаскелл, 48

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

Менее гольф:

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

объяснение

sequenceКомбинатор Haskell берет список действий и выполняет их, возвращая результат каждого действия в списке. Например:

sequence [getChar, getChar, getChar]

эквивалентно:

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

В Haskell действия обрабатываются как значения и склеиваются друг с другом с помощью >>=(bind) и returnпримитивов. Любой тип может быть «действием», если он реализует эти операторы, имея экземпляр Monad .

Между прочим, у типа списка есть экземпляр монады. Например:

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

Это равно [(1,4),(1,5),(1,6),(2,4),(2,5),(2,6),(3,4),(3,5),(3,6)]. Обратите внимание, что понимание списка поразительно похоже:

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

Поскольку списки являются типом «действия», мы можем использовать sequenceсо списками. Выше может быть выражено как:

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

Таким образом, sequenceдает нам комбинации бесплатно!

Итак, для построения списка:

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

Мне просто нужно создать списки для передачи sequence

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

Затем используйте concatMapдля применения sequenceк спискам и объединения полученных списков. По совпадению, concatMapэто =<<функция для списков, поэтому монада списков позволяет мне побрить несколько символов и здесь.



3

Рубин, 35 знаков

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

Использование:

puts e[16383]   # XFD

Примечание. Существует также более короткая версия (30 символов) с использованием рекурсии.

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

Но с помощью этой функции вам может потребоваться увеличить размер стека для больших чисел в зависимости от вашего интерпретатора 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''

Вы можете удалить 2 скобки, потянув +chr(65+i%26)внутрь и проверив i>=0, сохранив вам 1 символ :)
quasimodo

Вы также можете сбрить 4 персонажа, используя f=lambda i:вместо этогоdef f(i):return
Strigoides

на самом деле это не очень хорошо для номеров 37 и выше. Мне пришлось немного обновить этот код:f = lambda i: i >= 0 and f(math.floor(i / 26 - 1)) + chr(int(round(65 + i % 26))) or ''
user007

2

Скала, 62 персонажа

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

Использование:

println(f(16383))

возвращает:

XFD

Вы можете попробовать это на Просто Скала . Скопируйте и вставьте функцию и используйте, f(some integer)чтобы увидеть результат.


Вам не нужно ""+по elseделу.
Питер Тейлор

2

Excel VBA, 31 байт

Функция анонимного непосредственного окна VBE, которая принимает входные данные из ячейки [A1]и выводит их в непосредственное окно VBE

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


2

PHP, 30 байт

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

Запустите как трубу с `-nr 'или попробуйте онлайн .


Я уверен, что это не делает то, что требуется. После того, Zкак это пошло бы, [а не AA.
Vilx-

@ Vilx- Я принимаю это как доказательство того, что ты не знаешь много PHP. Я добавил TiO; посмотреть на себя.
Тит

Святой ... ты прав! Я довольно хорошо знаю PHP, но он настолько полон странных вещей, что невозможно все это знать. Именно эта странность сбила меня с толку. Здесь, есть upvote и мои извинения!
Вилкс

1

VBA / VB6 / VBScript (не Excel), 73 байта

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

Звонок s(16383)вернется XFC.


Добро пожаловать в PPCG! Можете ли вы добавить объяснение для пользователей, незнакомых с VB?
AdmBorkBork

1
@AdmBorkBork Не так много, чтобы добавить к предыдущим ответам, просто привязка к языку!
LS_ᴅᴇᴠ

Похоже, что это не i>675s(676)=A@@YZs(677)=A@AZA
Тейлор Скотт

1
@TaylorScott Ты прав.
Работаем

1
@TaylorScott Исправлено, +6 байт ... Спасибо.
LS_ᴅᴇᴠ

1

Javascript, 147 байт

У меня была аналогичная проблема. Это гольф решения. Столбцы Excel являются биективными основаниями-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))}

Расширено, кроме использования 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
Вы можете добавить ссылку TIO. Кроме этого отличный первый ответ. Также добро пожаловать в PPCG.
Мухаммед Салман

Также не очень хорошая идея ответить на вопрос, заданный 7 лет назад.
Мухаммед Салман

Хорошо, НВМ, это неправильно на многих уровнях, как я никогда не видел это
Мухаммед Салман

Я хотел задать этот вопрос, но это был дубликат. Я не уверен, что вы получаете на @MuhammadSalman
MattH

Я вернусь к вам через минуту, в любом случае добро пожаловать в PPCG. хороший ответ. Пожалуйста, обратите внимание, что при написании ответа вы должны предоставить полную программу или функцию
Мухаммед Салман

1

Java, 57 байт (рекурсивно)

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

Попробуйте онлайн.

Объяснение:

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 байта (итеративный)

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

Попробуйте онлайн.

Объяснение:

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

Здравствуй. Извините, но я украл ваш код: здесь . :)
Мухаммед Салман

@ MuhammadSalman Хехе, нет проблем. Я на самом деле получил мой ответ от Scala . ;)
Кевин Круйссен

1

Forth (gforth) , 59 байтов

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

Попробуйте онлайн!

объяснение

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 байт

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

Альтернативная рекурсивная версия, 68 байт:

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

Тестовый скрипт:

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

Выход:

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

Примечание: Powershell не предоставляет divоператора.


0

Хаскелл, 48

Я действительно думал, что смогу обыграть другую запись на Haskell, но увы ...

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

Я уверен, что от этого можно сбрить пару символов, но я не программировал на Хаскеле почти год, так что я довольно ржавый.

Это не совсем то, что вы бы назвали элегантным.


Неплохо! :) Но Ха - после более чем 3 лет, все еще нет решения C #. : D
Vilx-

Ха-ха, действительно. Но решение C # тривиально написать с использованием этого же метода. string f(int n){return n<0?"":f(n/26-1)+(char)(n%26+65);}57 символов, так что я бы почти почувствовал себя плохо, разместив его как ответ.
Форс

0

Jq 1,5 , 71 байт

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

Ожидает ввода в N. например

def N:16383;

Expanded:

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

Попробуйте онлайн!



Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.