Qual é esse número no Shortlex?


15

A maioria dos computadores armazena números inteiros em binário, mas os produz em decimal. No entanto, decimal é apenas uma representação; por acaso, achamos conveniente.

Esse desafio é escrever algum código para gerar um valor inteiro em decimal shortlex .

O que é isso?
http://en.wikipedia.org/wiki/Shortlex_order

Shortlex assume o comprimento da sequência de dígitos como o principal significante do valor. A sequência, iniciando a partir de uma sequência vazia que representa zero, é ...

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

(Pense nas colunas do Excel, mas usando apenas os dígitos decimais.)

Escreva um programa ou função que aceite um número inteiro e retorne uma cadeia de caracteres correspondente à representação decimal em shortlex desse número inteiro, conforme descrito acima.

Valores de teste:

0 → "" (String vazia)
1 → "0"
10 → "9"
11 → "00"
42 → "31"
100 → "89"
800 → "689"
1060 → "949"
10270 → "9159"
100501 → "89390"


2
Pode ser importante observar que a sequência 19, 20, 21, 22em decimais é mapeada para 08, 09, 10, 11em shortlex. Por isso eu confundi isso 100 -> 89!
Sean Latham


6
Observe que o que você está chamando de "decimal shortlex" de um número também é o numeral bijetivo de base dez , com os símbolos {0,1,2,3,4,5,6,7,8,9} substituídos pelo dígitos usuais {1,2,3,4,5,6,7,8,9, A}. Por exemplo, 2014 na notação bijetiva usual de base dez é 1A14 e, em shortlex decimal, é 0903.
res

Respostas:


34

JavaScript (ES6) 42 74

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

Teste no console do FireFox

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

Resultado

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

Como eu pensei nisso?

Dado um número fixo de dígitos, a sequência de saída é simplesmente crescente, para que haja um delta fixo entre entrada e saída. Dar uma olhada:

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

Mas os 0s iniciais são difíceis de gerenciar, então eu tenho um truque padrão, adicione um primeiro dígito e trabalhe o módulo (ou seja, corte o primeiro dígito na saída). Então -1-> +9, -11 -> +89, -111 -> +889 e assim por diante.
Última etapa: não ligo para o que é o primeiro dígito, portanto, não há necessidade de verificar se o número de entrada é <ou> maior que 111 ... (honestamente, achei isso por tentativa e erro)

Teste

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>


8
Eu não tenho idéia do por que isso funciona.
Martin Ender

Por que você faz em n-~(n+'')vez de apenas n-~n?
Claudiu

@ Claudiu é (n+'').replace(...), substituir obras em seqüências de caracteres, não números.
edc65

@ edc65: Opa, sim, peguei agora, desencontro meus parênteses. Dayum isso é muito brilhante
Claudiu

3
@Dennis fique à vontade para portá-lo. Você já está ganhando
edc65 9/09/14

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

Ele funciona apenas para valores abaixo de 256, pois o Marbelous é uma linguagem de 8 bits.

Como funciona

Marbelous é uma linguagem 2D com valores representados por bolinhas de 8 bits que caem uma célula em cada tick, a menos que algum dispositivo impeça a queda. Este programa Marbelous consiste em 3 placas; vamos começar com o mais fácil:

:O
}0
+Z
+C
{0

:Oé o nome do painel (para ser mais preciso, O é o nome e: diz ao interpretado que esta linha é um nome. Ao dar um nome aos painéis, outros painéis podem chamá-los }0como um dispositivo de entrada, isso pode ser visto como um Esta célula será substituída por um mármore de entrada (valor) quando a função for chamada. +Zadiciona 35 a qualquer mármore que passa por ele e o deixa cair. +Cfaz o mesmo, mas adiciona 12. {0é uma célula de saída , quando um mármore atingir essa célula, a função sairá e retornará o valor nesse dispositivo de saída.

Portanto, todos juntos, este quadro assume um valor e, em seguida, acrescenta 47. Para nós, isso significa que transforma qualquer número de dígito único no código ASCII do dígito -1 (é claro que isso também funcionará para 10).

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

Este fórum está um pouco mais complicado. Você deve conseguir identificar :Icomo o nome da placa e localizar alguns dispositivos de entrada e saída. Você notará que temos dois dispositivos de entrada diferentes }0e }1. Isso significa que esta função recebe 2 entradas. Você também notará que existem duas instâncias do }1dispositivo. Ao chamar a função, essas duas células conterão o mesmo valor. O }0dispositivo de entrada está diretamente acima de um \/dispositivo, atua como uma lata de lixo e remove qualquer mármore que cair sobre ela imediatamente.

Vamos dar uma olhada no que acontece com uma das bolinhas colocadas no quadro pelos }1dispositivos de entrada:

}1
=9 &1
&0
{>

Ele cairá no primeiro tique e atingirá o =9dispositivo. Isso compara o valor do mármore a 9 e permite que o mármore caia, se a instrução =9avaliar. O mármore é empurrado para a direita, se não. &0e &1são sincronizadores. Eles seguram bolas de gude que caem sobre eles até que todos os outros &nsincronizadores sejam preenchidos também. Como você pode esperar, isso provocará condicionalmente comportamentos diferentes em alguma outra parte do quadro.

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

Se eu lhe disser que ++é um incrementador, você já deverá saber com o que os diferentes sincronizadores serão preenchidos. A esquerda &1conterá o valor de entrada }1+ 1, o &0próximo a ele conterá 0 ( 00é um literal de idioma, representado em hexadecimal). O segundo &1conterá o valor 1 e o direito &0será preenchido com um F7, que subtrai 9 de um valor, uma vez que a adição no Marbelous é o módulo 256.

// é um dispositivo defletor, que empurra qualquer mármore para a esquerda em vez de deixá-lo cair.

Juntar tudo isso dá a você o seguinte: se o mármore }1for 9, os &0sincronizadores serão preenchidos. Isso fará com que o valor 0 caia na {0saída e F7(ou -9) na {1saída. Se }1não for 9, {0será preenchido com }1+ 1 e {0conterá 1. Há também um {>dispositivo, esta é uma saída especial que gera uma bola de gude próxima a uma placa em vez de embaixo dela. Isso será preenchido }1se for igual a 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

Ok, agora para o grande. Este quadro não tem um nome explícito, pois é o quadro principal do arquivo. Seu nome implícito é Mb. Você deve conseguir reconhecer algumas células. Há um dispositivo de entrada, alguns literais de idioma ( 00e FF). Existem alguns sincronizadores e há um defletor. vamos percorrer este pedaço por pedaço.

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

Portanto, o valor de entrada (a entrada da linha de comando, pois essa é a placa principal) começa na segunda célula a partir do topo, onde }0está localizado. Ele cairá e alcançará o >0dispositivo, que é outro dispositivo de comparação. qualquer mármore maior que 0 cai, qualquer outro mármore é empurrado para a direita. (como as variáveis ​​Marbelous não são assinadas, apenas exatamente 0 será empurrado para a direita). Esse mármore de valor zero atingirá o @6dispositivo. Este é um portal e transporta o mármore para outro portal correspondente, neste caso, logo acima dele. O mármore 0 alcançará o &0sincronizador e acionará algumas coisas em outro lugar.

Se o mármore não for 0, ele cai, é desviado para a direita por \\acertos --que o diminuem em um e depois caem em /\um clonador. Este dispositivo pega uma bola de gude e produz uma cópia para a direita e outra para a esquerda. A esquerda será levada para o outro, @0onde o mármore passará pela mesma sequência novamente. A esquerda será levada para outro lugar. Isso nos dá um loop, que diminui a entrada da linha de comando uma vez por loop e aciona algum comportamento em cada loop até atingir 0. Ele então aciona outro comportamento.

Vamos dar uma olhada no que acontece com o mármore colocado em @4cada loop.

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

Existem três literais de idioma aqui ( FF), que caem imediatamente em portais. Esses portais os levarão para três dos IIdispositivos. IIrefere-se ao quadro :Ique definimos mais adiante no arquivo. Como :Ipossui 2 dispositivos de entrada distintos, sua representação em outra placa deve ter 2 células de largura. Como temos 6 células contendo II, podemos dizer que temos 3 instâncias dessa função no quadro.

Os FFmármores (ou 256 ou -1, se desejar) ficarão nas células de entrada da :Ifunção, esperando até que haja mármore de entrada suficiente para iniciar a função (mais um). É aí que o @4portal entra. Uma cópia da entrada da linha de comando decrementada cai em cada loop. Isso acionará a :Iplaca mais à esquerda . Inicialmente com os valores 256 (ou -1) e qualquer que seja a entrada da linha de comando foi -1. O mármore esquerdo será colocado nos }0dispositivos do :Itabuleiro e o direito no }1. Se você se lembrar do que este fórum fez, poderá saber qual é o resultado. Ele produzirá uma versão incrementada da entrada direita na saída esquerda (e transforma um 9 em 0, e não 10) e gera 1 ou -9 à direita.

O valor incrementado será levado de volta para a célula de entrada correta por um portal e o valor à direita cai em um sincronizador. Se um sincronizador já estiver segurando uma bola de gude, as duas bolas de gude colidem. Os mármores em colisão são adicionados no módulo 256. Portanto, os valores nos sincronizadores farão o seguinte: eles começam vazios, depois passam para 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 e depois para 1 novamente (desde 247 é adicionado o módulo 256).

Você também deve se lembrar que uma bola de gude obtém a saída para a direita quando o valor de entrada volta para 0. Como as :Iplacas estão próximas umas das outras, isso ativará a placa à direita uma vez. Isso preencherá os três sincronizadores com valores que são um mais altos do que deveriam ser uma representação abreviada da entrada da linha de comando, no momento em que esse loop for reduzido a 0.

Você também deve se lembrar que a :Ofunção transforma um valor no valor ascii do dígito que representa o valor -1. A saída dessas OOcélulas cairá da placa, que imprime seus caracteres ASCII correspondentes em STDOUT.

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

Então, o que acontece quando a linha de comando de mármore atinge 0 e preenche esses &0sincronizadores? bem, algumas bolinhas de valor 0 caem e acionam os três sincronizadores que estão segurando os dígitos (+ 1) do número shortlex na parte inferior do quadro. &3é acionado primeiro, pois contém o dígito mais significativo, depois é &2seguido por &1. Esse mármore é teleportado para o outro @5dispositivo antes de atingir a !!célula, que termina o tabuleiro.


4
Parece que também pode ser um código Perl válido
Doorknob

12

CJam, 14 11 bytes

l40f-Ab)s1>

Experimente online.

Como funciona

Essa abordagem é fortemente baseada na resposta do edc65 (com sua permissão explícita ):

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

Exemplo de execução

$ 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
Isso é obsceno
Claudiu

3
+1 para encontrar uma maneira de reduzi-lo ainda mais
edc65

6

Python 2 (38) (43)

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

Sem substituição de caracteres, apenas aritmética.

Ungolfed:

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

Não tenho uma boa razão para a recursão funcionar, apenas encaixo esse padrão na lista de valores. Se você alterasse cada um n-1para n, obteria a representação regular de dígitos.

Para jogar golfe, costumo ~-ncalcular n-1com maior precedência que /10ou %10, economizando em parênteses. O n*'_'é apenas para produzir a cadeia vazia quando n=0e qualquer outra cadeia caso contrário. O '_'pode ser qualquer cadeia para esta finalidade.


4

Ruby, 70 68 66 64 57 bytes

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

Define uma função a ser chamada como f[42]. Aqui está o detalhamento do algoritmo:

  • Trate 0separadamente.
  • Subtraia potências de 10 até a próxima potência de 10 não se encaixar mais no número.
  • Transforme o número em uma string preenchida com zeros à esquerda.

Os créditos para a idéia de usar uma string de formato vão para Falko!


Como alternativa, usando a abordagem do edc65:

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

São 45 bytes e só incluo, porque não estou superando ele. ;)


Certo. Eu acho que não vou te pegar de qualquer maneira com meu longo código Python. ;)
Falko

@Optimizer Tenho certeza de que, se alguém usasse essa abordagem em um dos idiomas de golfe, ficaria abaixo de 20. (Dito isto, não consigo chegar aos 44 em Ruby com essa abordagem ... atualmente aos 45)
Martin Ender

2
@ Otimizador Não concordo com isso. Para iniciantes, J e APL não são linguagens de golfe e ganham tantas vezes quanto GolfScript e CJam. Além disso, o golfe não é sobre a marca de seleção verde, mas sobre vencer as inscrições "em sua liga". Se eu escrever uma inscrição em Ruby que supera todos os quatro idiomas, posso ficar muito feliz com isso, e não preciso que eles sejam banidos para desfrutar de golfe em idiomas mais detalhados. De fato, um golfe inteligente em uma linguagem "normal" como a da edc tem muito mais chances de ganhar votos do que uma implementação ingênua (mas mais curta) em uma linguagem de golfe.
Martin Ender

3

Haskell, 67 bytes

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

essa solução basicamente adiciona 1 o número especificado de vezes, em notação abreviada.

uso:

>f 9
"8"
>f 100
"89"

3

CJam, 16 bytes

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

Experimente online. Requer pelo menos O (n) tempo e memória, então deixe 100501 para o intérprete offline ...

Como funciona

A idéia básica por trás dessa abordagem é calcular pelo menos N decimais shortlex em sua ordem natural e descartar tudo, exceto o enésimo. Não é muito eficiente, mas curto.

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.                                       ";

Exemplo de execução

$ 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 bytes

Porto da resposta inteligente do @ edc65 , com as melhorias do @ Dennis :

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

Resultado:

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

Resposta anterior:

Bash + coreutils, 71 54 bytes

Aqui está uma maneira ligeiramente diferente de fazer isso:

jot -w%x $1$1|tr 0-9a a0-9|grep -P ^\\d+$|sed $1!d 2>-
  • jot saídas aumentando números inteiros hexadecimais
  • tr converte isso em (0,1, ..., 8,9, b, ... f, 0a, 00,01, ..., 99,9b, ..., ff, 0aa, ..., 000 , ...)
  • grep simplesmente filtra todas as linhas que contêm dígitos para fornecer (0,1, ..., 8,9,00, ..., 99.000 ....)
  • sed exclui tudo, exceto a enésima linha
  • STDERR é redirecionado para um arquivo descartável '-', de modo que simplesmente obtemos a string vazia quando 0 é passado ( sedconta os números de linha começando em 1, portanto, erros se 0 é passado)
  • Como estamos filtrando números com grep, precisamos gerar mais números inteiros base 11 com seq/ dcque o número de entrada. Repetir os dígitos de n é mais que suficiente.

Note que uma vez que o número shortlex é impresso, seqcontinua gerando números até $1$1, o que diminui especialmente para números de entrada maiores - O (n²), eu acho. Podemos acelerar, seqfechando imediatamente após a impressão, ao custo de 7 bytes:

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

Não há requisito de velocidade na pergunta, por isso vou com a versão mais curta para minha resposta principal.


@ Otimizador não: tente s='jot -w%x $1$1|tr 0-9a a0-9|grep -P ^\\d+$|sed $1!d 2>-'; echo ${#s}. Eu suspeito que você possa estar usando python para medir o comprimento da string, que trata o "\\" como um caractere.
Digital Trauma

2
Minha resposta mudou até agora, mas se eu fiz algo inteligente na primeira revisão, foi inteiramente por acidente. Foi um por direto da resposta de edc65; os 8 são todos dele ... - A variável auxiliar $aparece ser desnecessária; cut -b2-<<<$[$1-~${1//?/8}]deve funcionar muito bem.
Dennis

1
@ Dennis Certo, eu vejo. Obrigado pela sugestão!
Digital Trauma

2

Python 2- 84, 70 66

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

Abordagem alternativa (mesmo comprimento):

n=input()
k=len(`9*(n+1)/10`)
print"%%0%dd"%k%(n-int('1'*k))*(n>0)

Usar uma string de formato é inteligente! Espero que você não se importe se eu usar isso também. :)
Martin Ender

2

Python 3, 107 caracteres

Isso não acabou vencendo, mas achei inteligente:

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]

Eu defino um gerador para toda a sequência em 64 caracteres. Infelizmente, eu tenho que passar por algumas contorções para obter o enésimo elemento do gerador ... se eu pudesse S=lambda n:G()[n].


2

Pyth , 12

Outro ponto da resposta da @ edc65, que é o vencedor claro (IMO):

t`+hQv*l`Q\8

Pacote de teste (Graças a @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"

Explicação:

Q = eval(input())             Implicit.
t`                            All but the first digit of
  +hQ                         Q+1 + 
   v                          eval(
    *l`Q                      len(repr(Q)) * 
     \8                       "8"

CJam vs Pyth; a batalha continua. : P
Dennis

Tentei dar a Pyth uma chance para esse desafio, mas não consegui encontrar uma maneira de transformar uma lista em um número inteiro (por exemplo [8, 8, 9] -> 889). Como você faz isso?
Dennis

@Dennis Para ir da lista para o int, você basicamente precisa passar por uma string. jktransformará sua lista em uma string ev transformará isso em um int. Então vjk[8 8 9]vai dar o número 889.
isaacg

OK obrigado. Infelizmente, a conversão de strings impossibilita alguns truques. Com conversão base CJam / GolfScript, [2 -1] -> 19e [1 11] -> 21.
Dennis

1
@ Dennis Sim, quando eu adicionar a conversão básica ao Pyth, isso funcionará. Mas eu ainda não.
Isaacg


1

Haskell , 57 bytes

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

Experimente online!

Constrói uma lista infinita de números e índices abreviados para a resposta. g nconstrói a enésima "geração" de números, acrescentando o próximo dígito na frente de cada um dos números da geração anterior.



0

Excel, 37 bytes

Usando a abordagem do @ edc65:

=REPLACE(REPT(8,LEN(A1))+A1+1,1,1,"")

0

Gelatina , 5 bytes

ḃ⁵ịØD

Experimente online!

Sou muito novo no Jelly, por isso, se você puder melhorar isso, comente!

Explicação:

ḃ⁵ịØ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)

(De acordo com o comentário de res acima, o problema é equivalente a converter o número em base bijetiva 10)

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.