Перетворення бази з рядками


16

Вступ

У нас в минулому було декілька базових проблем перетворення, але не так багато було розроблено для вирішення довільних чисел довжини (тобто числа, достатньо довгі, щоб вони переповнювали цілий тип даних), і тих, які більшість відчували себе трохи складний. Мені цікаво, як можна змінити такий базовий код, як цей.

Виклик

Напишіть програму або функцію на обраній вами мові, яка може перетворити рядок однієї бази в рядок іншої бази. Вхідним елементом має бути число, яке потрібно перетворити (рядок), від-base (число базової-10), базове (число базового-10) та набір символів (рядок). На виході має бути перетворене число (рядок).

Деякі подальші деталі та правила такі:

  • Число для перетворення буде невід'ємним цілим числом (так як -і .може бути в наборі символів). Так буде і вихід.
  • Провідні нулі (перший символ у наборі символів) слід обрізати. Якщо результат дорівнює нулю, повинна залишитися одна нульова цифра.
  • Мінімальний підтримуваний базовий діапазон становить від 2 до 95, що складається з друкованих символів ascii.
  • Вхід для числа, яке потрібно перетворити, набору символів та виводу має бути типом даних рядка. Бази повинні мати цілочисельний тип даних базового 10 (або цілочисельні плавці).
  • Довжина рядка вхідного числа може бути дуже великою. Важко підрахувати розумний мінімум, але сподівайтеся, що він зможе обробляти щонайменше 1000 символів та виконати 100 символів за менш ніж 10 секунд на пристойній машині (дуже щедрий для подібних проблем, але я не хочу швидкість бути фокусом).
  • Ви не можете використовувати вбудовані функції зміни бази.
  • Введення набору символів може бути в будь-якому розташуванні, а не тільки в типових 0-9a-z ... і т.д.
  • Припустимо, що буде використовуватися лише дійсний ввід. Не турбуйтеся про помилки.

Переможець визначатиметься за найкоротшим кодом, який відповідає критеріям. Вони будуть відібрані щонайменше за 7 базових 10 днів, або якщо / коли було достатньо заявок. У разі вирівнювання, переможець стане кодом, який працює швидше. Якщо швидкість / продуктивність достатньо близька, відповідь, що прийшла раніше, перемагає.

Приклади

Ось кілька прикладів введення та виводу, з якими ваш код повинен вміти обробляти:

F("1010101", 2, 10, "0123456789")
> 85

F("0001010101", 2, 10, "0123456789")
> 85

F("85", 10, 2, "0123456789")
> 1010101

F("1010101", 10, 2, "0123456789")
> 11110110100110110101

F("bababab", 2, 10, "abcdefghij")
> if

F("10", 3, 2, "0123456789")
> 11

F("<('.'<)(v'.'v)(>'.'>)(^'.'^)", 31, 2, "~!@#$%^v&*()_+-=`[]{}|';:,./<>? ")
> !!~~~~~~~!!!~!~~!!!!!!!!!~~!!~!!!!!!~~!~!~!!!~!~!~!!~~!!!~!~~!!~!!~~!~!!~~!!~!~!!!~~~~!!!!!!!!!!!!~!!~!~!~~~~!~~~~!~~~~~!~~!!~~~!~!~!!!~!~~

F("~~~~~~~~~~", 31, 2, "~!@#$%^v&*()_+-=`[]{}|';:,./<>? ")
> ~

F("9876543210123456789", 10, 36, "0123456789abcdefghijklmnopqrstuvwxyz")
> 231ceddo6msr9

F("ALLYOURBASEAREBELONGTOUS", 62, 10, "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")
> 6173180047113843154028210391227718305282902

F("howmuchwoodcouldawoodchuckchuckifawoodchuckcouldchuckwood", 36, 95, "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ~`!@#$%^&*()_-+=[{]}\\|;:'\",<.>/? ")
> o3K9e(r_lgal0$;?w0[`<$n~</SUk(r#9W@."0&}_2?[n

F("1100111100011010101010101011001111011010101101001111101000000001010010100101111110000010001001111100000001011000000001001101110101", 2, 95, "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ~`!@#$%^&*()_-+=[{]}\\|;:'\",<.>/? ")
> this is much shorter

У нас був один, розроблений для вирішення довільних чисел довжини.
Пітер Тейлор

@PeterTaylor Добре бовтався, якось пропустив це в моєму пошуку. Все-таки я б стверджував, що вони досить різні. Інший включає набір символів за замовчуванням, багатобайтові послідовності, обробку помилок та перетворення послідовності в послідовність. Все це додає набагато більшого розмаху у відповідях та зосереджується на різних оптимізаціях. Цей виклик значно зменшений і призведе до зовсім іншого коду від іншого завдання (окрім основного алгоритму).
Mwr247

@PeterTaylor Plus, інше питання було задано 4 роки тому, і він отримав лише дві дійсні відповіді (і з однією вже прийнятою, мало підстав для того, щоб нарікатися). Я готовий зробити ставку, що громада сподобається цьому виклику, малий вплив від попереднього або почуття "повторюваності".
Mwr247

7
Хоча цей виклик дуже схожий на попередній, я насправді виступаю за те, щоб закрити попередній як невідповідний. Цей виклик набагато чіткіше і якісніший, ніж старий.
Мего

Не могли б ви детальніше розібратися You cannot use built in change-of-base functions to convert the entire input string/number at once? Зокрема, чи можу я використовувати вбудований для перетворення входу на проміжну базу? Чи можу я потім використовувати вбудований для перетворення на цільову базу? Хоче щось convert input with canonical form for given base; convert to base 10; convert to target base; convert back to specified character set with string replacement?
Мего

Відповіді:


5

CJam, 34 байти

0ll:Af#lif{@*+}~li:X;{XmdA=\}h;]W%

Формат введення - input_N alphabet input_B output_Bкожен в окремому рядку.

Запустити всі тестові справи.

Пояснення

0     e# Push a zero which we'll use as a running total to build up the input number.
l     e# Read the input number.
l:A   e# Read the alphabet and store it in A.
f#    e# For each character in the input number turn it into its position in the alphabet,
      e# replacing characters with the corresponding numerical digit value.
li    e# Read input and convert to integer.
f{    e# For each digit (leaving the base on the stack)...
  @*  e#   Pull up the running total and multiply it by the base.
  +   e#   Add the current digit.
}
~     e# The result will be wrapped in an array. Unwrap it.
li:X; e# Read the output base, store it in X and discard it.
{     e# While the running total is not zero yet...
  Xmd e#   Take the running total divmod X. The modulo gives the next digit, and
      e#   the division result represents the remaining digits.
  A=  e#   Pick the corresponding character from the alphabet.
  \   e#   Swap the digit with the remaining value.
}h
;     e# We'll end up with a final zero on the stack which we don't want. Discard it.
]W%   e# Wrap everything in an array and reverse it, because we've generated the 
      e# digits from least to most significant.

Це працює для того ж числа байтів:

L0ll:Af#lif{@*+}~li:X;{XmdA=@+\}h;

Єдина відмінність полягає в тому, що ми створюємо рядок, а не збираємо все на стеку і повертаємо його назад.


7

Python 2 , 115 114 106 105 94 байт

Пропозиції з гольфу вітаються. Спробуйте в Інтернеті!

Редагувати: -9 байт завдяки mbomb007 -2 байти завдяки FlipTack.

def a(n,f,t,d,z=0,s=''):
 for i in n:z=z*f+d.find(i)
 while z:s=d[z%t]+s;z/=t
 print s or d[0]

Безголівки:

def arbitrary_base_conversion(num, b_from, b_to, digs, z=0, s=''):
    for i in num:
        z = z * b_from + digs.index(i)
    while z:
        s = digs[z % b_to] + s
        z = z / t
    if s:
        return s
    else:
        return d[0]

1
while z:s=d[z%t]+s;z/=tекономить 9 байт.
mbomb007

Ви можете поставити z=0і s=''в декларацію функції для збереження байтів.
FlipTack

використовуючи printзамість returnце дозволено за умовчанням .
FlipTack

6

Серйозно, 50 байт

0╗,╝,2┐,3┐,4┐╛`4└í╜2└*+╗`MX╜ε╗W;3└@%4└E╜@+╗3└@\WX╜

Шестнадцятковий дамп:

30bb2cbc2c32bf2c33bf2c34bfbe6034c0a1bd32c02a2bbb60
4d58bdeebb573b33c0402534c045bd402bbb33c0405c5758bd

Я пишаюся цим, незважаючи на його довжину. Чому? Тому що це чудово спрацювало з другої спроби. Я написав це і налагодив буквально за 10 хвилин. Зазвичай налагодження серйозної програми - це година праці.

Пояснення:

0╗                                                  Put a zero in reg0 (build number here)
  ,╝,2┐,3┐,4┐                                       Put evaluated inputs in next four regs
             ╛                                      Load string from reg1
              `         `M                          Map over its chars
               4└                                   Load string of digits
                 í                                  Get index of char in it.
                  ╜                                 Load number-so-far from reg0
                   2└*                              Multiply by from-base
                      +                             Add current digit.
                       ╗                            Save back in reg0
                          X                         Discard emptied string/list.
                           ╜                        Load completed num from reg0
                            ε╗                      Put empty string in reg0
                              W                W    While number is positive
                               ;                    Duplicate
                                3└@%                Mod by to-base.
                                    4└E             Look up corresponding char in digits
                                       ╜@+          Prepend to string-so-far.
                                                      (Forgetting this @ was my one bug.)
                                          ╗         Put it back in reg0
                                           3└@\     integer divide by to-base.
                                                X   Discard leftover 0
                                                 ╜  Load completed string from reg0
                                                    Implicit output.

3

C (функція) з бібліотекою GMP , 260

Це виявилося довше, ніж я сподівався, але тут все одно. Цей mpz_*матеріал дійсно їсть багато байтів. Я спробував #define M(x) mpz_##x, але це дало чистий приріст у 10 байт.

#include <gmp.h>
O(mpz_t N,int t,char*d){mpz_t Q,R;mpz_inits(Q,R,0);mpz_tdiv_qr_ui(Q,R,N,t);mpz_sgn(Q)&&O(Q,t,d);putchar(d[mpz_get_ui(R)]);}F(char*n,int f,int t,char*d){mpz_t N;mpz_init(N);while(*n)mpz_mul_ui(N,N,f),mpz_add_ui(N,N,strchr(d,*n++)-d);O(N,t,d);}

Функція F()- точка входу. Він перетворює вхідний рядок у mpz_tпослідовні множення на from-базу та додавання індексу даної цифри у розрядний список.

Функція O()- це рекурсивна вихідна функція. Кожна рекурсія divmods mpz_tпо to-BASE. Оскільки це дає вихідні цифри у зворотному порядку, рекурсія ефективно дозволяє зберігати цифри у стеку та виводити у правильному порядку.

Тест-драйвер:

Нові рядки та відступи додаються для читабельності.

#include <stdio.h>
#include <string.h>

#include <gmp.h>
O(mpz_t N,int t,char*d){
  mpz_t Q,R;
  mpz_inits(Q,R,0);
  mpz_tdiv_qr_ui(Q,R,N,t);
  mpz_sgn(Q)&&O(Q,t,d);
  putchar(d[mpz_get_ui(R)]);
}
F(char*n,int f,int t,char*d){
  mpz_t N;
  mpz_init(N);
  while(*n)
    mpz_mul_ui(N,N,f),mpz_add_ui(N,N,strchr(d,*n++)-d);
  O(N,t,d);
}

int main (int argc, char **argv) {
  int i;

  struct test_t {
    char *n;
    int from_base;
    int to_base;
    char *digit_list;
  } test[] = {
    {"1010101", 2, 10, "0123456789"},
    {"0001010101", 2, 10, "0123456789"},
    {"85", 10, 2, "0123456789"},
    {"1010101", 10, 2, "0123456789"},
    {"bababab", 2, 10, "abcdefghij"},
    {"10", 3, 2, "0123456789"},
    {"<('.'<)(v'.'v)(>'.'>)(^'.'^)", 31, 2, "~!@#$%^v&*()_+-=`[]{}|';:,./<>? "},
    {"~~~~~~~~~~", 31, 2, "~!@#$%^v&*()_+-=`[]{}|';:,./<>? "},
    {"9876543210123456789", 10, 36, "0123456789abcdefghijklmnopqrstuvwxyz"},
    {"ALLYOURBASEAREBELONGTOUS", 62, 10, "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"},
    {"howmuchwoodcouldawoodchuckchuckifawoodchuckcouldchuckwood", 36, 95, "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ~`!@#$%^&*()_-+=[{]}\\|;:'\",<.>/? "},
    {"1100111100011010101010101011001111011010101101001111101000000001010010100101111110000010001001111100000001011000000001001101110101", 2, 95, "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ~`!@#$%^&*()_-+=[{]}\\|;:'\",<.>/? "},
    {0}
  };

  for (i = 0; test[i].n; i++) {
    F(test[i].n, test[i].from_base, test[i].to_base, test[i].digit_list);
    puts("");
  }

  return 0;
}

3

JavaScript (ES6), 140 байт

(s,f,t,m)=>[...s].map(c=>{c=m.indexOf(c);for(i=0;c||i<r.length;i++)r[i]=(n=(r[i]|0)*f+c)%t,c=n/t|0},r=[0])&&r.reverse().map(c=>m[c]).join``

На відміну від коду @ Mwr247 (який використовує арифметику base-f, щоб ділити s на кожен раз, збираючи кожен залишок у міру його використання), я використовую арифметику base-t, щоб помножувати відповідь на f кожного разу, додаючи кожну цифру s, коли я йду.

Безголівки:

function base(source, from, to, mapping) {
    result = [0];
    for (j = 0; j < s.length; s++) {
        carry = mapping.indexOf(s[j]);
        for (i = 0; carry || i < result.length; i++) {
            next = (result[i] || 0) * from + carry;
            result[i] = next % to;
            carry = Math.floor(next / to);
         }
    }
    string = "";
    for (j = result.length; j --> 0; )
        string += mapping[result[j]];
    return string;
}

3

Рубі, 113 112 105 98 97 95 87 байт

Я якось подвійно розмістив свою відповідь Python (якось), тож ось відповідь Рубі. Ще сім байтів завдяки манатурці , ще один байт завдяки Мартіну Бюттнеру та ще 8 байт завдяки cia_rana .

->n,f,t,d{z=0;s='';n.chars{|i|z=z*f+d.index(i)};(s=d[z%t]+s;z/=t)while z>0;s[0]?s:d[0]}

Безголівки:

def a(n,f,t,d)
  z=0
  s=''
  n.chars do |i|
    z = z*f + d.index(i)
  end
  while z>0 
    s = d[z%t] + s
    z /= t
  end
  if s[0]   # if n not zero
    return s
  else
    return d[0]
  end
end

Як щодо використання s=d[z%t]+s;z/=tзамість z,m=z.divmod t;s=d[m]+s?
cia_rana

3

APL, 10 байт

{⍺⍺[⍵⍵⍳⍵]}

Це оператор APL. В APL і використовуються для передачі значень, тоді як ⍵⍵і ⍺⍺зазвичай використовуються для передачі функцій. Я зловживаю цим, щоб мати 3 аргументи. ⍺⍺є лівим аргументом, ⍵⍵є "внутрішнім" правим аргументом і є "зовнішнім" правим аргументом.

В основному: ⍺(⍺⍺{...}⍵⍵)⍵

Тоді все, що потрібно, - це знайти позиції вхідного рядка в таблиці "від", а потім використовувати []для індексації в таблиці "до" ці позиції.

Приклад:

    ('012345'{⍺⍺[⍵⍵⍳⍵]}'abcdef')'abcabc'
012012

2

JavaScript (ES6), 175 байт

(s,f,t,h)=>eval('s=[...s].map(a=>h.indexOf(a));n=[];while(s.length){d=m=[],s.map(v=>((e=(c=v+m*f)/t|0,m=c%t),e||d.length?d.push(e):0)),s=d,n.unshift(m)}n.map(a=>h[a]).join``')

Зрозумів, що вже досить довго я можу подати той, який я зробив для створення прикладів. Можливо, я спробую трохи пізніше спробувати його в гольф.


Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.