Conversão de Base Mista

12

fundo

A maioria das pessoas aqui deve estar familiarizada com vários sistemas básicos: decimal, binário, hexadecimal, octal. Por exemplo, no sistema hexadecimal, o número 12345 16 representaria

1*16^4 + 2*16^3 + 3*16^2 + 4*16^1 + 5*16^0

Observe que geralmente não esperamos que a base (aqui 16) mude de dígito para dígito.

Uma generalização desses sistemas posicionais usuais permite usar uma base numérica diferente para cada dígito. Por exemplo, se estivéssemos alternando entre sistema decimal e binário (começando com a base 10 no dígito menos significativo), o número 190315 [2,10] representaria

1*10*2*10*2*10 + 9*2*10*2*10 + 0*10*2*10 + 3*2*10 + 1*10 + 5 = 7675

Denotamos essa base como [2,10]. A base mais à direita corresponde ao dígito menos significativo. Então você percorre as bases (à esquerda) enquanto percorre os dígitos (à esquerda), contornando se há mais dígitos do que bases.

Para ler mais, consulte a Wikipedia .

O desafio

Escreva um programa ou função que, dada uma lista de dígitos, Duma base de entrada Ie uma base de saída O, converta o número inteiro representado por Dde base Iem base O. Você pode receber entradas via STDIN, ARGV ou argumento de função e retornar o resultado ou imprimi-lo em STDOUT.

Você pode assumir:

  • que os números em Ie Osão todos maiores que 1.
  • o Ie Onão estão vazios.
  • que o número de entrada é válido na base fornecida (ou seja, nenhum dígito maior que sua base).

Dpode estar vazio (representando 0) ou pode ter zeros à esquerda. Sua saída não deve conter zeros à esquerda. Em particular, um resultado representando 0deve ser retornado como uma lista vazia.

Você não deve usar nenhuma função de conversão básica interna ou de terceiros.

Isso é código de golfe, a resposta mais curta (em bytes) vence.

Exemplos

D               I                  O        Result
[1,0,0]         [10]               [2]      [1,1,0,0,1,0,0]
[1,0,0]         [2]                [10]     [4]
[1,9,0,3,1,5]   [2,10]             [10]     [7,6,7,5]
[1,9,0,3,1,5]   [2,10]             [4,3,2]  [2,0,1,1,0,1,3,0,1]
[52,0,0,0,0]    [100,7,24,60,60]   [10]     [3,1,4,4,9,6,0,0]
[0,2,10]        [2,4,8,16]         [42]     [1,0]
[]              [123,456]          [13]     []
[0,0]           [123,456]          [13]     []
Martin Ender
fonte
Posso exigir uma lista infinita como descrição básica ou tenho que infinitificá-la eu mesmo?
John Dvorak
@JanDvorak Quer dizer, se você pode esperar que as listas de base já tenham um número suficiente de repetições para cobrir todos os dígitos? Não, você terá que se envolver ou se repetir.
Martin Ender
Presumo que a obtenção de uma lista vazia como base seja UB, mas podemos supor que a lista de dígitos não esteja vazia? Além disso, qual é a política para rastrear zeros?
John Dvorak
Ou seja, eu não me importo uma lista vazia na entrada, mas eu gostaria de produzir []se a entrada é[0]
John Dvorak
Posso solicitar e produzir uma lista de dígitos na ordem inversa (primeiro LSD)?
John Dvorak

Respostas:

6

CJam, 45

q~_,@m>0@{@(:T+@T*@+}/\;La{\)_@+@@md@@j@+}jp;

Finalmente eu encontrei um bom uso de j.

Como funciona

Long ArrayList Block jexecuta o bloco que recebe um número inteiro como parâmetro e Long jchama esse bloco recursivamente no bloco. Ele também armazenará os valores retornados pelo bloco em uma matriz interna, que é inicializada pelo parâmetro da matriz. Ele não executará o bloco se a entrada já estiver na matriz e o valor na matriz for retornado.

Portanto, se eu inicializá-lo com uma matriz de uma matriz vazia, a matriz vazia será retornada para a entrada 0 e o bloco será executado para qualquer outra entrada.

q~_,@m>0@{@(:T+@T*@+}/\;     " See below. Stack: O decoded-D ";
La                           " Initialized the value with input 0 as empty list. ";
{
  \)_@+@@md@@                " See below. Stack: remainder O quotient ";
  j                          " Call this block recursively except when the same quotient has
                               appeared before, which is impossible except the 0.
                               Stack: remainder O returned_list ";
  @+                         " Append the remainder to the list. ";
}j
p;                           " Format and output, and discard O. ";

CJam, 49 48

q~_,@m>0@{@(:T+@T*@+}/\;{\)_@+@@md@@}h;;_{}?]W%`

Entrada deve ser O I D.

Exemplos:

$ while read; do <<<$REPLY ./cjam-0.6.2.jar <(echo 'q~_,@m>0@{@(:T+@T*@+}/\;{\)_@+@@md@@}h;;_{}?]W%`');echo; done
[2] [10] [1 0 0]
[10] [2] [1 0 0]
[10] [2 10] [1 9 0 3 1 5]
[4 3 2] [2 10] [1 9 0 3 1 5]
[10] [100 7 24 60 60] [52 0 0 0 0]
[42] [2 4 8 16] [0 2 10]
[13] [123 456] []
[13] [123 456] [0 0]
[1 1 0 0 1 0 0]
[4]
[7 6 7 5]
[2 0 1 1 0 1 3 0 1]
[3 1 4 4 9 6 0 0]
[1 0]
""
""

Como funciona

q~           “ Read the input and evaluate. ";
_,@m>        " Rotate I to the right by the length of D. ";
0@{          " For each item in D, with the result initialized to 0: ";
  @(:T+      " Rotate I to the left, and set the original first item to T. ";
  @T*@+      " Calculate result * T + current. ";
}/
\;           " Discard I. ";
{            " Do: ";
  \)_@+      " Rotate O to the right, and get a copy of the original last item. ";
  @@md       " Calculate divmod. ";
  @@         " Move O and the quotient to the top of the stack. ";
}h           " ...while the quotient is not 0. ";
;;           " Discard O and the last 0. ";
_{}?         " If the last item is still 0, discard it. ";
]W%          " Collect into an array and reverse. ";
`            " Turn the array into its string representation. ";
jimmy23013
fonte
Eu tenho que parar de usar a rotação de array apenas porque CJam tem ... Esse _{}?truque é realmente legal.
Dennis
@sudo {}e|é o mesmo.
jimmy23013
Você se importaria de adicionar uma explicação para a versão usando j? :)
Martin Ender
@ MartinBüttner Concluído.
jimmy23013
3

CJam, 62 61 59 57 bytes

q~Wf%~UX@{1$*@+\@(+_W=@*@\}/;\;{\(+_W=@\md@@}h;;]W%_0=!>p

Lê as matrizes de entrada a partir [O I D]de STDIN. Experimente online.

Como funciona

q~         " Read from STDIN and evaluate the input. Result: [O I D]                      ";
Wf%~       " Reverse each of the three arrays and dump them on the stack.                 ";
UX@        " Push U (0) and X (1); rotate D on top of both.                               ";
{          " For each N in D:                                                             ";
  1$*      "   N *= X                                                                     ";
  @+       "   U += N                                                                     ";
  \@(+     "   I := I[1:] + I[:1]                                                         ";
  _W=@*    "   X *= I[-1]                                                                 ";
  @\       "   ( U I X ) ↦ ( I U X )                                                      ";
}/         "                                                                              ";
;\;        " Discard I and X.                                                             ";
{          " R := []; Do:                                                                 ";
  \(+      "   O := O[1:] + O[:1]                                                         ";
  _W=@\md  "   R += [U / O[-1]], U %= O[-1]                                               ";
  @@       "   ( O U R[-1] ) ↦ ( R[-1] O U )                                              ";
}/         " While U                                                                      ";
;;]        " Discard U and O.                                                             ";
W%         " Reverse R.                                                                   ";
_0=!>      " Execute R := R[!R[0]:] to remove a potential leading zero.                   ";
p          " Print a string presentation of R.                                            ";

Casos de teste

$ cjam mixed-base.cjam <<< '[ [2]     [10]             [1 0 0]       ]'
[1 1 0 0 1 0 0]
$ cjam mixed-base.cjam <<< '[ [10]    [2]              [1 0 0]       ]'
[4]
$ cjam mixed-base.cjam <<< '[ [10]    [2 10]           [1 9 0 3 1 5] ]'
[7 6 7 5]
$ cjam mixed-base.cjam <<< '[ [4 3 2] [2 10]           [1 9 0 3 1 5] ]'
[2 0 1 1 0 1 3 0 1]
$ cjam mixed-base.cjam <<< '[ [10]    [100 7 24 60 60] [52 0 0 0 0]  ]'
[3 1 4 4 9 6 0 0]
$ cjam mixed-base.cjam <<< '[ [42]    [2 4 8 16]       [0 2 10]      ]'
[1 0]
$ cjam mixed-base.cjam <<< '[ [13]    [123 456]        []            ]'
""
$ cjam mixed-base.cjam <<< '[ [13]    [123 456]        [0 0]         ]'
""

Observe que cadeias vazias e matrizes vazias são indistinguíveis do CJam, portanto, []pimprime "".

Dennis
fonte
4
OMG Nunca vi um programa CJam de 62 bytes: D
Optimizer
@Optimizer Esta é provavelmente a minha inscrição mais longa no CJam.
Esolanging Fruit
@ Dennis Isso não era código de golfe , era?
Esolanging Fruit
@ Challenger5 Não era, mas duvido que uma versão para golfe fosse menor que 200 bytes.
Dennis
2

Python 2 - 318

from operator import *
d,i,o=input()
c=len
def p(l):return reduce(mul,l,1)
n=sum(x[1]*p((i[-x[0]%c(i)-1:]+x[0]/c(i)*i)[1:]) for x in enumerate(d[::-1]))
r=[]
j=1
t=[]
k=c(o)
while p(t)*max(o)<=n:t=(o[-j%k-1:]+j/k*o)[1:];j+=1
while j:j-=1;t=(o[-j%k-1:]+j/k*o)[1:];r+=[n/p(t)];n%=p(t)
print (r if r[0] else [])

Eu estraguei a ordem dos argumentos por acidente, então tive que revertê-los. Vou trabalhar com o slice-fu para que as listas funcionem na outra direção mais tarde, já perdi todo o meu intervalo para o almoço: p

Fixo

FryAmTheEggman
fonte
Não diga "desperdício";)
Martin Ender
Você deve ser capaz de jogar golfe com até 286 bytes: repl.it/JbIk
Zacharý
@ Zacharý Este foi o meu primeiro golfe, eu acho, tenho certeza que pode ser muito menor do que isso! A resposta de Feersum demonstra isso muito bem, eu acho. Se você quiser, pode editar esta resposta, mas receio que não esteja particularmente motivado para melhorá-la.
FryAmTheEggman
2

APL, 78

{1↓(⊃1⌷⍺)({t←⍺[(⍴⍺)|⍴⍵]
(⌊0⌷⍵÷t)(t|0⌷⍵),1↓⍵}⍣{0=0⌷⍵}),+/(0,⍵)×⌽×\1,(⍴⍵)⍴⌽⊃0⌷⍺}

Exemplos:

f←{1↓(⊃1⌷⍺)({t←⍺[(⍴⍺)|⍴⍵]
  (⌊0⌷⍵÷t)(t|0⌷⍵),1↓⍵}⍣{0=0⌷⍵}),+/(0,⍵)×⌽×\1,(⍴⍵)⍴⌽⊃0⌷⍺}
(,10)(,2) f 1 0 0
1 1 0 0 1 0 0
(,2)(,10) f 1 0 0
4
(2 10)(,10) f 1 9 0 3 1 5
7 6 7 5
(2 10)(4 3 2) f 1 9 0 3 1 5
2 0 1 1 0 1 3 0 1
(100 7 24 60 60)(,10) f 52 0 0 0 0
3 1 4 4 9 6 0 0
(2 4 8 16)(,42) f 0 2 10
1 0
(123 456)(,13) f ⍬

⍴(123 456)(,13) f ⍬
0
(123 456)(,13) f 0 0

⍴(123 456)(,13) f 0 0
0
jimmy23013
fonte
Apenas para o ensino geral - com built-ins: {{⍵↓⍨1⍳⍨×⍵}(99⍴⎕)⊤⍵⊥⍨⎕⍴⍨⍴⍵}leva D como argumento direita, em seguida, pede I e O.
Adám
2

Python 2-122

Muito simples, não conseguiu encontrar nenhum truque especial de golfe neste.

def f(D,I,O):
 n,i,l=0,-len(D),[]
 for d in D:n=n*I[i%len(I)]+d;i+=1
 while n:i-=1;b=O[i%len(O)];l=[n%b]+l;n/=b
 return l

Ungolfed:

def f(D,I,O):
    n = 0
    for i in range(len(D)):
        dn = len(D) - i
        n = n * I[-dn % len(I)] + D[i]
    l = []
    i = 0
    while n:
        i -= 1
        b = O[i%len(O)]
        l = [n%b] + l
        n /= b
    return l

Edit: versão de programa de 116 bytes graças a FryAmTheEggman

D,I,O=input()
n,i,l=0,-len(D),[]
for d in D:n=n*I[i%len(I)]+d;i+=1
while n:i-=1;b=O[i%len(O)];l=[n%b]+l;n/=b
print l

Esta versão aceita entrada separada por vírgula, por exemplo [1,9,0,3,1,5], [2,10], [10]

feersum
fonte
@FryAmTheEggman Não sei bem como aceitar entradas com aspas, mas separar as matrizes por vírgulas funciona.
feersum
1

k2 - 83 74 char

Função tendo um argumento. Isso foi muito mais adequado para K que J, e é por isso que não estou usando J. Seria apenas um monte de lixo de boxe / unboxing, e ninguém quer isso. Isso está no dialeto k2 (pode exigir alguma adaptação para funcionar no Kona de implementação de código aberto), mas vou mudar para k4 se puder diminuí-lo mais lá.

{:[#x@:|&~&\~x;|*{x 1}.[{_(x,y!*z;y%*z;1!z)}]/(();+/x*1*\(1-#x)#y;|z);()]}

Observarei que defendo a escolha aqui e digo que uma lista de itens deve ser inserida como tal. ,2é uma lista de um item, sendo o item escalar 2. Freqüentemente escalares e listas de um item são intercambiáveis, mas existe uma lógica nesse golfe que se baseia na suposição de argumentos de lista.

Para explicar o golfe, vou dividi-lo em duas partes. Fé o golfe, Lé o loop principal que calcula a saída. O mecanismo exato do loop é Laplicado repetidamente a seus argumentos até o segundo argumento ser zero e, em seguida, esse resultado é retornado. (Esta é a .[L]/parte.)

L: {_(x,y!*z;y%*z;1!z)}
F: {:[#x@:|&~&\~x;|*{x 1}.[L]/(();+/x*1*\(1-#x)#y;|z);()]}

Por explosão:

{_(x,y!*z;y%*z;1!z)}  /function, args x y z
  (      ;    ;   )   / update each arg as follows:
               1!z    /  new z: rotate z left
            *z        /  head of z (current base digit)
          y%          /  y divided by that
 _                    /  new y: floor of that
     y!*z             /  y modulo head of z
   x,                 /  new x: append that to old x

{:[#x@:|&~&\~x;|*{x 1}.[L]/(();+/x*1*\(1-#x)#y;|z);()]}  /function, args x y z
            ~x                                           /find the 0s in x
          &\                                             /find leading zeros
        &~                                               /indices of digits that aren't
    x@ |                                                 /those items from x, reverse order
    x :                                                  /assign to x
 :[#          ;                                      ]   /if length is 0:
                                                   ()    / return empty list
                                                  ;      /else:
                      .[L]/                              / loop L repeatedly
                 {x 1}                                   / until y = 0
                           (  ;               ;  )       / starting with args:
                            ()                           /  Lx: empty list
                                       1-#x              /  number of input digits, minus 1
                                      (    )#y           /  cyclically extend base leftward
                                   1*\                   /  running product, start at 1
                                 x*                      /  multiply digits by these
                               +/                        /  Ly: sum of the above
                                               |z        /  Lz: out base, reverse order
               |*                                        / first elem of result, reversed

Em ação:

  {:[#x@:|&~&\~x;|*{x 1}.[{_(x,y!*z;y%*z;1!z)}]/(();+/x*1*\(1-#x)#y;|z);()]}[1 0 0; ,10; ,2]
1 1 0 0 1 0 0
  f:{:[#x@:|&~&\~x;|*{x 1}.[{_(x,y!*z;y%*z;1!z)}]/(();+/x*1*\(1-#x)#y;|z);()]}
  f[1 0 0; ,2; ,10]
,4
  f .' ((1 9 0 3 1 5; 2 10;           ,10)  /f apply each
>       (1 9 0 3 1 5; 2 10;           4 3 2)
>       (52 0 0 0 0;  100 7 24 60 60; ,10)
>       (0 2 10;      2 4 8 16;       ,42)
>       (();          123 456;        ,13)
>       (0 0;         123 456;        ,13))
(7 6 7 5
 2 0 1 1 0 1 3 0 1
 3 1 4 4 9 6 0 0
 1 0
 ()
 ())
algoritmshark
fonte
0

Perl 6 , 67 bytes

{[R,] [+]([R,](@^a)Z*1,|[\*] |[R,](@^b)xx*).polymod: |[R,](@^c)xx*}

Tente

Expandido:

{  # bare block lambda with placeholder parameters @a,@b,@c

  [R,]    # reduce the following using reverse meta op 「R」 combined with 「,」 op
          # (shorter than 「reverse」)

    [+](  # sum

        [R,](@^a) # reverse of first argument

      Z[*]        # zipped using &infix:<*> with the following

        1,
        |                    # slip the following in (flattens)
          [\*]               # triangle reduce

            |[R,](@^b) xx*   # reverse of second argument repeated infinitely
    )

    .polymod: |[R,](@^c) xx* # moduli the reverse of third argument repeated
}

Caso você não tenha certeza de qual redução de triângulo faz:

[\*] 1,2,3,4,5
# 1, 1*2, 1*2*3, 1*2*3*4, 1*2*3*4*5
# 1,   2,     6,      24,       120

Se eu pudesse pegar as entradas invertidas e gerar a saída inversa, seriam 47 bytes.

{[+](@^a Z*1,|[\*] |@^b xx*).polymod: |@^c xx*}

Tente

Brad Gilbert b2gills
fonte