Что это за номер в Shortlex?

15

Большинство компьютеров хранят целые числа в двоичном формате, но выводят их в десятичном виде. Однако десятичная дробь - это всего лишь одно представление, нам просто кажется, что это удобно.

Эта задача состоит в том, чтобы написать некоторый код для вывода целочисленного значения в коротком десятичном формате .

Что это?
http://en.wikipedia.org/wiki/Shortlex_order

Shortlex принимает длину последовательности цифр в качестве основного значения значения. Последовательность, начинающаяся с пустой строки, представляющей ноль, является ...

ε,0,1,...,8,9,00,01,...98,99,000,001,...,998,999,0000,...

(Подумайте о столбцах Excel, но используйте только десятичные цифры.)

Напишите программу или функцию, которая принимает целое число и возвращает строку, соответствующую кратко-десятичному представлению этого целого числа, как описано выше.

Тестовые значения:

0 → «» (пустая строка)
1 → «0»
10 → «9»
11 → «00»
42 → «31»
100 → «89»
800 → «689»
1060 → «949»
10270 → «9159»
100501 → "89390"

billpg
источник
2
Может быть важно отметить, что последовательность 19, 20, 21, 22в десятичном 08, 09, 10, 11формате отображается в коротком. Вот почему я так запутался 100 -> 89!
Шон Лэтэм
2
Связанные
Питер Тейлор
6
Обратите внимание, что то, что вы называете «коротким десятичным числом» числа, также является его биективной цифрой « основание-десять» с символами {0,1,2,3,4,5,6,7,8,9}, замененными на обычные цифры {1,2,3,4,5,6,7,8,9, A}. Например, 2014 в обычном биективном обозначении base-ten - 1A14, а в коротком десятичном - 0903.
Res

Ответы:

34

JavaScript (ES6) 42 74

n=>(n-~(n+'').replace(/./g,8)+'').slice(1)

Тест в консоли FireFox

;[0,1,10,11,42,100,800,1060,10270,100501]
.forEach(x => console.log(x +" -> '" + S(x) + "'"))

Выход

0 -> ''
1 -> '0'
10 -> '9'
11 -> '00'
42 -> '31'
100 -> '89'
800 -> '689'
1060 -> '949'
10270 -> '9159'
100501 -> '89390'

Как я об этом подумал?

При фиксированном количестве цифр выходная последовательность просто возрастает, поэтому между входом и выходом существует фиксированная дельта. Взглянуть:

  1..10 -> 0..9 (delta -1)
 11..110 -> 00..99 (delta -11)
111..1110 -> 000..999 (delta -111) mmm there's a pattern here...

Но ведущими 0 трудно управлять, поэтому у меня есть стандартная хитрость, добавить первую цифру и работать по модулю (то есть вырезать первую цифру в выводе). Затем -1-> +9, -11 -> +89, -111 -> +889 и так далее.
Последний шаг: мне все равно, какая первая цифра, поэтому нет необходимости проверять, является ли число iinput <или> чем 111 ... (честно, я нашел это методом проб и ошибок)

Тестовое задание

var F=
n=>(n-~(n+'').replace(/./g,8)+'').slice(1)

function update()
{
  var i=+I.value
  O.textContent = F(i)
}


update()
<input id=I value=99 type=number oninput='update()'><pre id=O></pre>

edc65
источник
8
Я понятия не имею, почему это работает.
Мартин Эндер
Почему вы делаете, n-~(n+'')а не просто n-~n?
Клавдиу
@Claudiu это (n+'').replace(...), заменить работает на строки, а не числа.
edc65
@ edc65: Ой, да, просто поймал это сейчас, не соответствует моим скобкам. Dayum это довольно блестяще
Клавдиу
3
@Dennis не стесняйтесь портировать его. Вы уже выигрываете
edc65
13

Marbelous 177 173 170

@0@6000000@5
}0&0&0&0&0
>0@6&3
\\--\/&2
@0/\@4\/&1!!
@4@1..@2@5@3
IIIIIIIIIIII
FF&1FF&2FF&3
@1OO@2OO@3OO
:I
}1..}10001F7
=9&1++..&1&0
&0}0&1&0{1{1
{>\/{0//
:O
}0
+Z
+C
{0

Он работает только для значений до 256, поскольку Marbelous - это 8-битный язык.

Как это устроено

Marbelous - это двумерный язык со значениями, представленными 8-битными шариками, которые падают на одну ячейку на каждом тике, если какое-либо устройство не предотвращает их падение. Эта Marbelous программа состоит из 3 досок; давайте начнем с самого простого:

:O
}0
+Z
+C
{0

:Oявляется названием доски (если быть точным, O является именем и: сообщает интерпретируемому, что эта строка является именем. Давая доскам имя, другие доски могут вызывать их }0как устройство ввода, это можно рассматривать как аргумент этой функции. Эта ячейка будет заменена входным мрамором (значением) при вызове функции. +Zдобавляет 35 к любому мрамору, который проходит над ним и позволяет ему проваливаться. +Cделает то же самое, но только добавляет 12. {0является выходной ячейкой Когда шарик достигнет этой ячейки, функция выйдет и вернет значение в этом устройстве вывода.

Итак, все вместе, эта доска принимает одно значение, а затем добавляет 47 к нему. Для нас это означает, что он превращает любое однозначное число в ascii-код цифры -1 (это, конечно, также будет работать для 10).

:I
}1 .. }1 00 01 F7
=9 &1 ++ .. &1 &0
&0 }0 &1 &0 {1 {1
{> \/ {0 //

Эта доска выглядит немного сложнее. Вы должны быть в состоянии идентифицировать :Iкак название платы и заметили некоторые устройства ввода и вывода. Вы заметите, что у нас есть два разных устройства ввода, }0и }1. Это означает, что эта функция принимает 2 входа. Вы также заметите, что есть два экземпляра }1устройства. При вызове функции обе эти ячейки будут содержать одно и то же значение. Устройство }0ввода находится прямо над \/устройством, оно действует как мусорная корзина и удаляет любой мрамор, который падает на него немедленно.

Давайте посмотрим, что происходит с одним из шариков, вставленных в плату }1устройствами ввода:

}1
=9 &1
&0
{>

Он упадет на первый тик и ударит =9устройство. Это сравнивает значение мрамора с 9 и позволяет мрамору провалиться, если утверждение выполнено =9до конца. Мрамор толкается вправо, если нет. &0и &1синхронизаторы. Они держатся за шарики, которые падают на них, пока все другие &nсинхронизаторы также не будут заполнены. Как вы можете ожидать, это условно вызовет другое поведение на некоторой другой части доски.

}1 00 01 F7
++ .. &1 &0
&1 &0 {1 {1
{0 //

Если я скажу вам, что ++это инкрементор, вы уже должны быть в состоянии сказать, чем будут заполнены различные синхронизаторы. Слева &1будет входное значение }1+ 1, &0рядом с ним будет 0 ( 00это языковой литерал, представленный в шестнадцатеричном формате). Второй &1будет содержать значение 1, а правое &0заполнено значением F7, которое вычитает 9 из значения, поскольку сложение в Marbelous равно по модулю 256.

// является дефлектором, который толкает любой мрамор влево, а не дает ему упасть.

Соединение всего этого дает вам следующее: если мрамор }1равен 9, &0синхронизаторы заполняются. Это приведет к тому, что значение 0 попадет на {0выход и F7(или -9) на {1выход. Если }1не 9, {0будет заполнено }1+ 1 и {0будет содержать 1. Существует также {>устройство, это специальный вывод, который выводит мрамор рядом с доской вместо нее. Это будет заполнено, }1если оно будет равно 9.

@0 @6 00 00 00 @5
}0 &0 &0 &0 &0
>0 @6 &3
\\ -- \/ &2
@0 /\ @4 \/ &1 !!
@4 @1 .. @2 @5 @3
II II II II II II
FF &1 FF &2 FF &3
@1 OO @2 OO @3 OO

Хорошо, теперь для большого. Эта доска не имеет явного имени, так как это основная доска файла. Его неявное имя Mb. Вы должны быть в состоянии распознать некоторые клетки. Есть устройство ввода, некоторые языковые литералы ( 00а FF). Есть несколько синхронизаторов и есть дефлектор. давайте пройдемся по этой части за частью.

@0 @6
}0 &0
>0 @6
\\ --
@0 /\ @4

Таким образом, входное значение (вход командной строки, поскольку это основная плата) начинается со второй ячейки сверху, где }0находится. Он упадет и достигнет >0устройства, которое является другим устройством сравнения. любой мрамор больше 0 проваливается, любой другой мрамор сдвигается вправо. (поскольку переменные Marbelous не имеют знака, только ровно 0 будут сдвинуты вправо). Этот мрамор нулевого значения затем попадет в @6устройство. Это портал, который переносит мрамор на другой соответствующий портал, в данном случае прямо над ним. Затем шарик 0 достигнет &0синхронизатора и вызовет некоторые вещи в другом месте.

Если мрамор не равен 0, он падает, отклоняется вправо от \\ударов, --которые уменьшают его на единицу, а затем падает на /\клонера. Это устройство берет мрамор и выводит одну его копию справа и одну слева. Левый @0переместится вверх к другому, где мрамор снова пройдет ту же последовательность. Левый будет взят в другом месте. Это дает нам цикл, который уменьшает ввод командной строки один раз за цикл и запускает некоторое поведение в каждом цикле, пока не достигнет 0. Затем запускается другое поведение.

Давайте посмотрим, что происходит с мрамором, вставленным в @4каждую петлю.

@4 @1 .. @2 @5 @3
II II II II II II
FF &1 FF &2 FF &3
@1 OO @2 OO @3 OO

Здесь есть 3 языковых литерала ( FF), которые сразу попадут в порталы. Эти порталы перенесут их на три IIустройства. IIотносится к доске, которую :Iмы определили ниже по файлу. Так как :Iимеет 2 разных устройства ввода, его представление на другой плате должно иметь ширину 2 ячейки. Поскольку у нас есть 6 ячеек II, мы можем сказать, что у нас есть 3 экземпляра этой функции на доске.

Мраморы FF(или 256, или -1, если хотите) будут находиться во входных ячейках :Iфункции в ожидании, пока не будет достаточно входного мрамора для запуска функции (еще одного). Вот где @4вступает портал. Копия уменьшенного ввода командной строки падает там в каждом цикле. Это активирует крайнюю левую :Iдоску. Изначально со значениями 256 (или -1) и любым другим значением ввода командной строки было -1. Левый мрамор будет помещен в }0устройства :Iдоски, а правый - в }1. Если вы вспомните, что сделала эта доска, вы сможете сказать, к чему это привело. Он выведет увеличенную версию правого входа на левом выходе (и он превратит 9 в 0, а не 10) и выведет 1 или -9 справа.

Увеличенное значение будет перенесено порталом обратно в правую входную ячейку, а значение справа попадет в синхронизатор. Если синхронизатор уже держит мрамор, два мрамора столкнутся. Столкнувшиеся шарики складываются по модулю 256. Таким образом, значения в синхронизаторах сделают следующее: они начинаются пустыми, а затем превращаются в 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, а затем в 1 снова (так как 247 добавляется по модулю 256).

Вы также можете помнить, что шарик выводится вправо, когда входное значение возвращается к 0. Так как :Iдоски находятся рядом друг с другом, эта команда сработает однажды вправо. Это заполнит три синхронизатора значениями, которые на одно больше, чем они должны быть, чтобы быть кратким представлением ввода командной строки, к тому времени, когда это зацикливается до 0.

Вы также можете помнить, что :Oфункция превращает значение в значение ascii цифры, которая представляет значение -1. Выход этих OOячеек будет падать с платы, которая печатает их соответствующие символы ascii в STDOUT.

00 00 00 @5
&0 &0 &0
&3
\/ &2
   \/ &1 !!
      @5

Так что же происходит, когда мрамор ввода командной строки достигает 0 и заполняет эти &0синхронизаторы? ну, несколько шариков со значением 0 падают и запускают три синхронизатора, которые содержат цифры (+ 1) номера короткого номера в нижней части платы. &3сначала срабатывает, так как содержит самую значимую цифру, затем &2следует &1. Этот мрамор затем телепортируется на другое @5устройство, прежде чем в конечном итоге попасть в !!ячейку, которая завершает доску.

overactor
источник
4
Выглядит так, как будто это тоже может быть допустимым кодом Perl
Doorknob
12

CJam, 14 11 байтов

l40f-Ab)s1>

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

Как это устроено

Этот подход в значительной степени основан на ответе edc65его явного разрешения ):

" Read a line L from STDIN. ";

l

" edc65's answer now forms an integer N by replacing each digit in L by an 8 and computes
  L - ~N = L + N + 1. Instead of adding L and N, we subtract 40 from each char code of L.
  Since the char code of the digit `D` is `D + 48`, this basically adds 8 to each digit.  ";

40f-

" Turn the resulting array into an integer by considering its elements a base 10 number.
  This is implemented as A ↦ A[-1] + 10 * A[-2] + 100 * A[-3] + ⋅⋅⋅, so it won't choke
  on digits greater than the base.                                                        ";

Ab

" Increment the integer on the stack to complete the calculation of L + N + 1.            ";

)

" Push the integers string representation and discard its first character.                ";

s1>

Пример запуска

$ for i in 0 1 10 11 42 100 800 1060 10270 100501
> do echo $i: $(cjam <(echo 'l40f-Ab)s1>') <<< $i)
> done
0:
1: 0
10: 9
11: 00
42: 31
100: 89
800: 689
1060: 949
10270: 9159
100501: 89390
Деннис
источник
1
Это непристойно
Клавдия
3
+1 за то, что нашел способ сократить его еще больше
edc65
6

Питон 2 (38) (43)

f=lambda n:n*'_'and f(~-n/10)+`~-n%10`

Нет замены символов, только арифметика.

Ungolfed:

def f(n):
    if n==0: return ''
    else: return f((n-1)//10) + str((n-1)%10)

У меня нет веской причины, почему рекурсия работает, я просто подгоняю этот шаблон к списку значений. Если вы измените каждый n-1на n, вы получите обычное представление цифр.

Для игры в гольф я использую ~-nвычисления n-1с более высоким приоритетом, чем /10или %10, экономя на паренсе. Это n*'_'просто для создания пустой строки, когда n=0и любая другая строка в противном случае. Для '_'этой цели может быть любая строка.

XNOR
источник
4

Рубин, 70 68 66 64 57 байт

f=->n{i=-1;n-=10**i while n>=10**i+=1;i<1?'':"%0#{i}d"%n}

Определяет функцию для вызова как f[42]. Вот грубая разбивка алгоритма:

  • Лечить 0отдельно.
  • Вычитайте силы 10, пока следующая сила 10 больше не вписывается в число.
  • Превратите число в строку, дополненную нулями слева.

Кредиты на идею использования форматной строки идут в Falko!


В качестве альтернативы, используя подход edc65:

f=->n{"#{n-~n.to_s.tr('^.',?8).to_i}"[1..-1]}

Это 45 байтов, и я только включаю его, потому что я не бью его этим. ;)

Мартин Эндер
источник
Конечно. Я думаю, я не поймаю вас в любом случае с моим длинным кодом Python. ;)
Фалько
@Optimizer Я уверен, что если бы кто-то использовал этот подход на одном из языков игры в гольф, у него было бы меньше 20. (Тем не менее, я не могу достичь 44 в Ruby с таким подходом ... в настоящее время на 45)
Мартин Конец
2
@ Оптимизатор Я не согласен с этим. Начнем с того, что J и APL не являются языками игры в гольф и выигрывают так же часто, как GolfScript и CJam. Более того, игра в гольф - это не зеленая галочка, а избиение представлений «в вашей лиге». Если я напишу представление на языке Ruby, которое превосходит все эти языки, кроме этих 4-х языков, я буду очень рад этому, и мне не нужны запреты на те из них, чтобы наслаждаться игрой в гольф на более многословных языках. На самом деле, умный гольф на «нормальном» языке, таком как edc, имеет гораздо больше шансов получить больше голосов, чем наивная (но более короткая) реализация на языке гольфа.
Мартин Эндер
3

Haskell, 67 байт

n('9':x)='0':n x
n(c:x)=succ c:x
n""="0"
f x=reverse$iterate n""!!x

это решение в основном добавляет 1 заданное количество раз в кратком обозначении.

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

>f 9
"8"
>f 100
"89"
гордый хаскеллер
источник
3

CJam, 16 байтов

li_)9*,{`1>}%_&=

Попробуйте онлайн. Требуется не менее O (n) времени и памяти, поэтому оставьте 100501 офлайновому переводчику ...

Как это устроено

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

li                " Read an integer N from STDIN.                                   ";
  _)9*            " Push M := (N + 1) * 9.                                          ";
      ,           " Push A := [ 0 1 ... M - 1 ].                                    ";
       {   }%     " For each I ∊ A:                                                 ";
       {`1>}%     " Push its string representation and discard the first character. ";
             _&   " Remove duplicates from the resulting array.                     ";
               =  " Retrieve the Nth element.                                       ";

Пример запуска

$ for i in 0 1 10 11 42 100 800 1060 10270 100501
> do echo $i: $(cjam <(echo 'li_)9*,{`1>}%_&=') <<< $i)
> done
0:
1: 0
10: 9
11: 00
42: 31
100: 89
800: 689
1060: 949
10270: 9159
100501: 89390
Деннис
источник
3

Bash + coreutils, 27 байт

Порт умного ответа @ edc65 , с улучшениями @ Денниса :

cut -b2-<<<$[$1-~${1//?/8}]

Выход:

$ for n in 0 1 10 11 42 100 110 111 800 1060 1110 1111 10270 100501; do echo "./shortlex.sh $n = \"$(./shortlex.sh $n)\""; done
./shortlex.sh 0 = ""
./shortlex.sh 1 = "0"
./shortlex.sh 10 = "9"
./shortlex.sh 11 = "00"
./shortlex.sh 42 = "31"
./shortlex.sh 100 = "89"
./shortlex.sh 110 = "99"
./shortlex.sh 111 = "000"
./shortlex.sh 800 = "689"
./shortlex.sh 1060 = "949"
./shortlex.sh 1110 = "999"
./shortlex.sh 1111 = "0000"
./shortlex.sh 10270 = "9159"
./shortlex.sh 100501 = "89390"
$ 

Предыдущий ответ:

Bash + coreutils, 71 54 байта

Вот немного другой способ сделать это:

jot -w%x $1$1|tr 0-9a a0-9|grep -P ^\\d+$|sed $1!d 2>-
  • jot выводит растущие шестнадцатеричные числа
  • tr преобразует это в (0,1, ..., 8,9, b, ... f, 0a, 00,01, ..., 99,9b, ..., ff, 0aa, ..., 000 , ...)
  • grep просто фильтрует все строки, содержащие цифры, чтобы дать (0,1, ..., 8,9,00, ..., 99,000 ....)
  • sed удаляет все кроме n-й строки
  • STDERR перенаправляется в одноразовый файл '-', так что мы просто получаем пустую строку, когда передается 0 ( sedподсчитывает номера строк, начинающиеся с 1, поэтому ошибки, если передается 0)
  • Поскольку мы отфильтровываем числа с помощью grep, нам нужно сгенерировать больше целых чисел с основанием 11 с seq/, dcчем входное число. Повторение цифр n более чем достаточно.

Обратите внимание, что после того, как номер короткого номера напечатан, он seqпродолжает генерировать числа до $1$1, что замедляется, особенно для больших входных чисел - O (n²), я думаю. Мы можем ускорить процесс, выполнив выход seqсразу же после печати, по цене 7 байт:

jot -w%x $1$1|tr 0-9a a0-9|grep -P ^\\d+$|sed -n $1{p\;q} 2>-

В этом вопросе нет требования к скорости, поэтому в качестве основного ответа я выберу более короткую версию.

Цифровая травма
источник
@ Оптимизатор Нет: попробуйте s='jot -w%x $1$1|tr 0-9a a0-9|grep -P ^\\d+$|sed $1!d 2>-'; echo ${#s}. Я подозреваю, что вы можете использовать python для измерения длины строки, которая обрабатывает «\\» как один символ.
Цифровая травма
2
Мой ответ уже изменился, но если я сделал что-то умное в первой ревизии, это было совершенно случайно. Это была прямая часть ответа edc65; все восьмерки - его ... - Вспомогательная переменная $aкажется ненужной; cut -b2-<<<$[$1-~${1//?/8}]должно работать просто отлично.
Деннис
1
@ Денис Хорошо, я вижу. Спасибо за предложение!
Цифровая травма
2

Питон 2 - 84, 70 66

n=input()
i=0
while n>=10**i:n-=10**i;i+=1
print"%%0%dd"%i%n*(i>0)

Альтернативный подход (такой же длины):

n=input()
k=len(`9*(n+1)/10`)
print"%%0%dd"%k%(n-int('1'*k))*(n>0)
Фалько
источник
Использование форматной строки - это умно! Надеюсь, вы не против, если я тоже этим воспользуюсь. :)
Мартин Эндер
2

Python 3, 107 символов

Это не закончилось победой, но я подумал, что это было умно:

def G():yield'';yield from(r+c for r in G()for c in'0123456789')
S=lambda n:list(zip(range(n+1),G()))[n][1]

Я определяю генератор для всей последовательности в 64 символов. К сожалению, я должен пройти через некоторые искажения, чтобы получить n-й элемент генератора ... если бы я только мог это сделать S=lambda n:G()[n].

Клаудиу
источник
2

Пиф , 12

Еще один порт ответа @ edc65, который является явным победителем (IMO):

t`+hQv*l`Q\8

Тестовый пакет (благодаря @DigitalTrauama):

$ for n in 0 1 10 11 42 100 110 111 800 1060 1110 1111 10270 100501; do echo "shortlex.pyth $n = \"$(pyth programs/shortlex.pyth <<< $n)\""; done
shortlex.pyth 0 = ""
shortlex.pyth 1 = "0"
shortlex.pyth 10 = "9"
shortlex.pyth 11 = "00"
shortlex.pyth 42 = "31"
shortlex.pyth 100 = "89"
shortlex.pyth 110 = "99"
shortlex.pyth 111 = "000"
shortlex.pyth 800 = "689"
shortlex.pyth 1060 = "949"
shortlex.pyth 1110 = "999"
shortlex.pyth 1111 = "0000"
shortlex.pyth 10270 = "9159"
shortlex.pyth 100501 = "89390"

Объяснение:

Q = eval(input())             Implicit.
t`                            All but the first digit of
  +hQ                         Q+1 + 
   v                          eval(
    *l`Q                      len(repr(Q)) * 
     \8                       "8"
isaacg
источник
CJam против Pyth; битва продолжается. : P
Деннис
Я попытался дать Pyth шанс на это испытание, но я не смог найти способ превратить List в целое число (например, [8, 8, 9] -> 889). Как ты это делаешь?
Деннис
@Dennis Чтобы попасть из списка в int, вам нужно пройти через строку. jkпревратит ваш список в строку, и vпревратит это в int. Так vjk[8 8 9]что дадим номер 889.
Исаак
Хорошо спасибо. К сожалению, преобразование строк делает некоторые трюки невозможными. С преобразованием базы CJam / GolfScript, [2 -1] -> 19и [1 11] -> 21.
Деннис
1
@ Деннис Да, когда я добавлю базовое преобразование в Pyth, это сработает. Но я еще не
Исаак
1

Haskell , 57 байт

((g=<<[0..])!!)
g 0=[""]
g n=[c:s|c<-['0'..'9'],s<-g$n-1]

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

Создает бесконечный список коротких номеров и индексов в нем для ответа. g nсоздает n-е «поколение» чисел, добавляя следующую цифру перед каждым из чисел в предыдущем поколении.

user1472751
источник
0

Excel, 37 байт

Используя подход @ edc65:

=REPLACE(REPT(8,LEN(A1))+A1+1,1,1,"")
Wernisch
источник
0

Желе , 5 байт

ḃ⁵ịØD

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

Я очень новичок в желе, поэтому, если вы можете улучшить это, пожалуйста, прокомментируйте!

Объяснение:

ḃ⁵ịØD   Main link.
ḃ       Convert to bijective base ...
 ⁵      10.
  ị     Each number (1 - 10) is converted to the character at its index in the string...
   ØD   “0123456789” (digits)

(Согласно комментарию res выше, проблема эквивалентна преобразованию числа в биективное основание 10)

user202729
источник