Toute votre base bijective nous appartient


25

Contexte

Une numération b de base bijective , où b est un entier positif, est une notation positionnelle bijective qui utilise des symboles b avec des valeurs associées de 1 à b .

Contrairement à son homologue non bijectif, aucun symbole n'a une valeur de 0 . De cette façon, chaque entier non négatif n a une représentation unique dans la base bijective b .

Les numérotations bijectives populaires incluent la base unaire, bijective 2 (utilisée dans le codage de longueur de bzip2 ) et la base bijective 26 (utilisée pour numéroter les colonnes dans les feuilles de calcul).

Définition

Dans ce défi, nous définissons l'ensemble M de symboles comme

123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz<=>

et une fonction i de M au nombre naturel tel que i ('1') = 1,…, i ('>') = 64 .

Etant donné une base b comprise entre 1 et 64 (tous deux inclus), nous définissons que chaque entier non négatif n correspond à la chaîne a k … a 0 , constituée de symboles de M , tels que n = b k i (a k ) + … + B 0 i (a 0 ) .

Cette correspondance est bien définie et bijective. Puisqu'une somme vide est définie comme 0 , l'entier 0 peut être codé comme une chaîne vide.

Tâche

Acceptez trois chaînes en entrée:

  • Une base d'entrée b comprise entre 1 et 64 , codée comme une chaîne de base bijective 64 .

  • Un entier non négatif n , codé comme une chaîne b de base bijective .

  • Une base de sortie B entre 1 et 64 , codée comme une chaîne de base bijective 64 .

Compte tenu de ces trois entrées, codez n comme une chaîne B de base bijective .

Cas de test

Tous les tests indiquent l'entrée dans l'ordre b , n , B .

Input:  "4" "" "8"
Output: ""

Input:  "A" "16" "2"
Output: "1112"

Input:  "2" "122" "A"
Output: "A"

Input:  "3" "31" "1"
Output: "1111111111"

Input:  ">" "Fe" "a"
Output: "RS"

Règles

  • Vous pouvez lire les trois chaînes dans n'importe quel ordre approprié, comme tel, un tableau de chaînes, une représentation de chaîne de celles-ci, concaténées ou séparées par des délimiteurs à caractère unique de votre choix.

  • Si vous choisissez d'imprimer la sortie sur STDOUT, vous ne pouvez imprimer que les symboles et (éventuellement) une nouvelle ligne de fin.

  • Les intégrations de conversion de base de toutes sortes sont autorisées.

  • Les règles de standard s'appliquent.

Réponses:


6

CJam, 43

qA,s"?[a{A<":,:^+:Mf#):B;(bLa{(Bmd)M=\j\+}j

3 octets supprimés avec l' aide de Dennis :) Essayez-le en ligne

Explication:

L'entrée est prise comme bnB, concaténée en une seule chaîne.

q           read the input
A,s         make an array of numbers from 0 to 9 and convert to string
"?[a{A<"    push this string, which contains the ends of 3 character ranges:
             uppercase letters: ['A'…'[')
             lowercase letters: ['a'…'{')
             "<=>": ['<'…'?')
             they're in a special order for the symmetric difference below
:,          for each character, make a range of all characters smaller than it
:^          fold/reduce these 6 ranges using symmetric difference
+           concatenate with the digits before
:M          save in M; this is like the M from the statement,
             except it starts with a zero (for matching indexes)
f#          find the indexes in M of all characters from the input string
)           take out the last value from the array
:B;         save it in B and pop it
(           take out the first value
b           use it as a base and convert the remaining array to a number
             this works even if some of the digits are not in the "normal" range
La{…}j      calculate with memoized recursion, using an empty string for value 0
  (         decrement the number
  Bmd       divide by B and get the quotient and remainder
  )         increment the remainder (this is the last digit in bijective base B)
  M=        get the corresponding character from M
  \j        swap with the quotient, and convert the quotient recursively
  \+        swap again and concatenate

Oh, vous pouvez réellement utiliser l'opérateur de conversion de base normal pour la première conversion de base? Maintenant, je me sens stupide d'utiliser tout le code que j'ai dans ma solution. :) Je ne savais pas que cela fonctionnerait avec des valeurs qui sont en dehors de la plage de la base. Eh bien, avec le recul, il n'y a aucune bonne raison pour que ce ne soit pas le cas.
Reto Koradi

@RetoKoradi oui, vous pouvez le faire; un jour cela sera documenté :)
aditsu

Cela vous dérange si je change ma solution pour utiliser la conversion de base? J'essaye normalement d'éviter de prendre des idées d'autres solutions. Mais cela me dérange vraiment de laisser le mien se tenir avec une telle approche sous-optimale. Il est fort probable que votre solution soit encore plus courte.
Reto Koradi

@RetoKoradi pas de problème, allez-y
aditsu

4

Pip, 84 80 78 octets

m:J[,tAZLCAZ"<=>"]p:$+(m@?^b)*(m@?a)**RV,#bs:m@?cWn:px:(mn-(p:n//s-!n%s)*s).xx

Dépôt GitHub pour Pip

Algorithmes adaptés de l'article Wikipédia. Voici l'explication d'une version antérieure légèrement non golfée:

                 Implicit: initialize a,b,c from cmdline args; t=10;
                 AZ=uppercase alphabet; x=""
m:               Build lookup table m:
 (J,t)             0123456789 (i.e. join(range(10)))...
 .AZ               plus A-Z...
 .LCAZ             plus lowercase a-z...
 ."<=>"            plus <=>
f:{              Define f(a,b) to convert a from bijective base b to decimal:
 $+                Sum of...
  (m@?^a)            list of index of each character of a in m
  *                  multiplied item-wise by 
  b**RV,#a           b to the power of each number in reverse(range(len(a)))
}
t:{              Define t(a,b) to convert a from decimal to bijective base b:
 x:""              Reset x to empty string (not needed if only calling the function once)
 Wa{               While a is not zero:
  p:a//b-!a%b        p = ceil(a/b) - 1 (= a//b if a%b!=0, a//b-1 otherwise)
  x:m@(a-p*b).x      Calculate digit a-p*b, look up the corresponding character in m, and
                     prepend to x
  a:p                p becomes the new a
 }
 x                 Return x
}
(t               Return result of calling t with these arguments:
 (f                Result of calling f with these arguments:
  b                  2nd cmdline arg
  m@?a)              1st cmdline arg's decimal value
 m@?c              3rd cmdline arg's decimal value
)
                 Print (implicit)

Exemple d'exécution:

dlosc@dlosc:~/golf$ python pip.py bijectivebase.pip ">" "Fe" "a"
RS

4

Octave, 166 octets

function z=b(o,x,n)
M=['1':'9','A':'Z','a':'z','<=>'];N(M)=1:64;n=N(n);x=polyval(N(x),N(o));z='';while x>0 r=mod(x,n);t=n;if r t=r;end;z=[M(t),z];x=fix(x/n)-(r<1);end

Version multiligne:

function z=b(o,x,n)
   M=['1':'9','A':'Z','a':'z','<=>'];
   N(M)=1:64;
   n=N(n);
   x=polyval(N(x),N(o));
   z='';
   while x>0
      r=mod(x,n);
      t=n;if r t=r;end;
      z=[M(t),z];
      x=fix(x/n)-(r<1);
   end
%end // implicit - not included above

Plutôt que de créer une carte pour convertir un caractère en une valeur d'index, je viens de créer la table de recherche inverse Npour les valeurs ascii 1..'z'et de la remplir avec les indices aux valeurs appropriées.

polyval évalue l'équation

c 1 x k + c 2 x k-1 + ... + c k x 0

en utilisant la valeur d'entrée convertie décimale comme vecteur de coefficients cet la base d'origine comme x. (Malheureusement, Octave base2dec()rejette les symboles hors de la plage normale.)

Une fois que nous avons la valeur d'entrée dans la base 10, le calcul de la valeur dans la nouvelle base est simple.

Pilote de test:

% script bijecttest.m
a=b('4','','8');
disp(a);
a=b('A','16','2');
disp(a);
a=b('2','122','A');
disp(a);
a=b('3','31','1');
disp(a);
a=b('>','Fe','a');
disp(a);

Résultats:

>> bijecttest

1112
A
1111111111
RS
>>

2

Perl, 261 248 229 octets

sub t{$b=0;$b*=$_[1],$b+=ord($1=~y/0-9A-Za-z<=>/\0-A/r)while$_[0]=~/(.)/g;return$b}sub r{$n=$_[0];$n-=$m=($n-1)%$_[1]+1,$d=(chr$m)=~y/\0-A/0-9A-Za-z<=>/r.$d,$n/=$_[1]while$n;print$d}@a=split/,/,<>;r(t(@a[1],t@a[0],64),t@a[2],64)

multi-lignes, alors que les boucles ne sont pas golfées:

sub t{ # convert bijective base string to number
    $b=0;
    while($_[0]=~/(.)/g)
        {$b*=$_[1];$b+=ord($1=~y/0-9A-Za-z<=>/\0-A/r)}
    return$b}
sub r{ # convert number to bijective base string
    $n=$_[0];
    while($n)
        {$n-=$m=($n-1)%$_[1]+1;$d=(chr$m)=~y/\0-A/0-9A-Za-z<=>/r.$d;$n/=$_[1]}
    print$d}
@a=split/,/,<>; # parse input
r(t(@a[1],t@a[0],64),t@a[2],64)

test une fonction pour analyser un nombre à partir d'une chaîne de base bijective d'une base donnée. rest une fonction pour générer une chaîne de base bijective d'une base donnée à partir d'un nombre. Les 3 paramètres séparés par des virgules sont analysés depuis stdin et les fonctions sont appelées selon les besoins.

La conversion d'un nombre positif en une chaîne de base bijective est similaire à une base normale. Cependant, où vous feriez quelque chose comme ça pour une base normale:

string s = ""
while(n)
{
    c = (n % base)
    s = (c + '0') + s
    n -= c // not necessary because the division will take care of it
    n /= base 
}

vous ajustez le mod pour donner une plage de 1 à la base au lieu de 0 à la base - 1:

string s = ""
while(n)
{
    c = (((n-1) % base)+1)
    s = (c + '0') + s
    n -= c  // necessary in the case c = base
    n /= base 
}

2

Python 2, ... 317 307 298 311 octets

Certainement golfable. Je déteste vraiment la façon dont les chaînes n'ont pas d'attribution d'élément et les listes n'ont pasfind . Je vais chercher un meilleur moyen que ma solution rapide que j'ai maintenant.

Ma méthode consiste à convertir l'entrée en nombre décimal, puis en base de sortie, puis de convertir cela en base bijective.

Edit : Trouvé que mon programme ne fonctionnait pas lors de la conversion en Unary. Il en coûte 13 octets pour réparer e=F(o)<2, etc.

Essayez-le ici

R=range;M="".join(map(chr,R(48,58)+R(65,91)+R(97,123)))+"<=>"
b,s,o=input()
F=M.find
e=F(o)<2
B=lambda n:n and B(n/F(o)-e)+M[n%F(o)+e]or""
n=B(sum(F(s[~j])*F(b)**j for j in R(len(s))))
i=n.find('0')
n=list(n)
while-~i:n=n[:i-1]+[M[F(n[i-1])-1]]+[o]+n[i+1:];n=n["0"==n[0]:];i="".join(n).find('0')
print"".join(n)

1
Je suis d'accord avec vos bêtes noires Python.
DLosc

@DLosc Merci pour l'aide au golf.
mbomb007

est-ce du bowling ? : P
Optimizer

Les listes ont la .index()méthode. Pourquoi ne pas utiliser cela au lieu de trouver? De plus, au lieu d'enregistrer F(b)et F(o)dans les variables, vous ne les utilisez qu'une seule fois, il vous suffit donc de les sous-insérer là où cela est nécessaire. Enfin, 'n'[2::5]est plus court que ''.join(n)(remplacer les apostrophes pour les contre-coups).
Kade

De plus, je pense que vous compliquez trop les choses. La conversion d'une chaîne de base bijective M en décimal ne devrait pas prendre plus de 35 à 40 octets. Décimal à une chaîne de base bijective B ne sera pas beaucoup plus que cela.
Kade

2

Python 2, 167 octets

Pas vraiment de trucs spéciaux ici, à part le [2::5]découpage pour obtenir le jeu de caractères à un nombre d'octets inférieur.

x=range;A=`map(chr,x(49,58)+x(65,91)+x(97,123))`[2::5]+'<=>'
r=A.find
b,n,B=input()
B=r(B)+1
d=0;s=''
for c in n:d=d*-~r(b)+r(c)+1
while d:d-=1;s=A[d%B]+s;d/=B
print s

Tests:

"4","","8"     >>> (empty string)
">","Fe","a"   >>> RS
"3","31","1"   >>> 1111111111
"A","16","2"   >>> 1112
"2","122","A"  >>> A

2

CJam, 73 70 69 55 51 48 octets

La dernière version utilise l'opérateur de conversion de base CJam pour la conversion à partir de la base source, à laquelle je n'avais pas pensé avant d'avoir vu la solution de @ aditsu. Il applique également une astuce récente de @Dennis pour la construction de la chaîne "digit" ( /codegolf//a/54348/32852 ), ainsi que d'autres idées partagées sur le chat.

lA,s'[,_el^+"<=>"+:Lf#Ll#bLl#:K;{(Kmd)L=\}hs-]W%

Le format d'entrée est la valeur, suivie de la base source et destination, chacune d'elles sur une ligne distincte. Pour la chaîne vide, laissez la première ligne vide. Exemple d'entrée:

122
2
A

Essayez-le en ligne

Explication:

l       Get and interpret value from input.
A,s     Build the list of 64 "digits". Start with [0..9]
'[,     Build character sequence from \0 to Z.
_el     Lower case copy of the same sequence.
^       Symmetric set difference gives only letters from both sequences.
+       Concatenate with sequence of decimal digits, creating [0..9A..Za..z].
"<=>"   Remaining 4 characters.
+       Concatenate, resulting in full 64 character "digit" string.
:L      ... and store it in variable L for repeated use.
f#      Look up input characters in digit list.
Ll#     Get source base from input, and look up value in digit list.
b       Base conversion. This produces the input value.
Ll#     Get destination base from input, and look up value in digit list.
:K;     Store it in variable K for use in loop, and pop it off stack.
{       Loop for generating output digits.
  (       Decrement to get ceiling minus 1 after division.
  Kmd     Calculate divmod of current value with destination base.
  )       Increment mod to get 1-based value for digit.
  L=      Look up digit character for digit value.
  \       Swap. Digit stays on stack for output, remaining value is processed
          in next loop iteration until it is 0.
}h      End of loop for generating output digits.
s       Final value is 0. Covert it to a string.
-       And subtract it from second but last value. This eliminates the 0,
        as well as the second but last value if it was a \0 character.
]       Wrap digits in array.
W%      Reverse array, to get result from MSB to LSB.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.