Chuyển đổi cơ sở với chuỗi


16

Giới thiệu

Trước đây, chúng tôi đã có một vài thách thức chuyển đổi cơ sở ở đây, nhưng không có nhiều thách thức được thiết kế để giải quyết các số có độ dài tùy ý (nghĩa là các số đủ dài để chúng vượt qua kiểu dữ liệu số nguyên) và trong số đó, hầu hết đều cảm thấy một chút phức tạp. Tôi tò mò làm thế nào để giảm bớt sự thay đổi của mã cơ sở như thế này.

Thử thách

Viết chương trình hoặc hàm bằng ngôn ngữ bạn chọn có thể chuyển đổi một chuỗi của một cơ sở thành một chuỗi của một cơ sở khác. Đầu vào phải là số được chuyển đổi (chuỗi), từ cơ sở (số cơ sở 10), sang cơ sở (số cơ sở 10) và bộ ký tự (chuỗi). Đầu ra phải là số chuyển đổi (chuỗi).

Một số chi tiết và quy tắc khác như sau:

  • Số cần chuyển đổi sẽ là số nguyên không âm (vì -.có thể nằm trong bộ ký tự). Vì vậy, cũng sẽ là đầu ra.
  • Các số 0 đứng đầu (ký tự đầu tiên trong bộ ký tự) nên được cắt bớt. Nếu kết quả bằng 0, một chữ số 0 duy nhất sẽ vẫn còn.
  • Phạm vi cơ sở được hỗ trợ tối thiểu là từ 2 đến 95, bao gồm các ký tự ascii có thể in được.
  • Đầu vào cho số được chuyển đổi, bộ ký tự và đầu ra đều phải là kiểu dữ liệu chuỗi. Các cơ sở phải là kiểu dữ liệu số nguyên cơ sở 10 (hoặc số nguyên nổi).
  • Độ dài của chuỗi số đầu vào có thể rất lớn. Thật khó để định lượng mức tối thiểu hợp lý, nhưng hy vọng nó có thể xử lý ít nhất 1000 ký tự và hoàn thành 100 ký tự trong chưa đầy 10 giây trên một máy tốt (rất hào phóng cho loại vấn đề này, nhưng tôi không muốn tốc độ để trở thành trọng tâm).
  • Bạn không thể sử dụng các chức năng thay đổi cơ sở tích hợp.
  • Đầu vào bộ ký tự có thể được sắp xếp theo bất kỳ cách nào, không chỉ là 0-9a-z ... vv.
  • Giả sử rằng chỉ có đầu vào hợp lệ sẽ được sử dụng. Đừng lo lắng về việc xử lý lỗi.

Người chiến thắng sẽ được xác định bởi mã ngắn nhất hoàn thành các tiêu chí. Họ sẽ được chọn trong ít nhất 7 cơ sở-10 ngày, hoặc nếu / khi đã có đủ bài nộp. Trong trường hợp hòa, mã chạy nhanh hơn sẽ là người chiến thắng. Nếu đủ gần về tốc độ / hiệu suất, câu trả lời đến sớm hơn sẽ thắng.

Ví dụ

Dưới đây là một vài ví dụ về đầu vào và đầu ra mà mã của bạn sẽ có thể xử lý:

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

Chúng tôi đã có một thiết kế để giải quyết các số chiều dài tùy ý.
Peter Taylor

@PeterTaylor Vâng dang, bằng cách nào đó đã bỏ lỡ cái đó trong tìm kiếm của tôi. Tuy nhiên, tôi sẽ tranh luận họ là đủ khác nhau. Một cái khác liên quan đến một bộ ký tự mặc định, các chuỗi nhiều byte, xử lý lỗi và chuyển đổi chuỗi thành chuỗi. Tất cả những điều này thêm vào sự phình to hơn nhiều trong các câu trả lời, và tập trung vào các tối ưu hóa khác nhau. Thử thách này được cắt giảm nhiều hơn và sẽ dẫn đến mã hoàn toàn khác với thử thách khác (thiếu thuật toán cốt lõi).
Mwr247

@PeterTaylor Plus, câu hỏi khác đã được hỏi 4 năm trước và chỉ nhận được hai câu trả lời hợp lệ (và với một câu trả lời đã được chấp nhận, rất ít lý do để trả lời). Tôi sẵn sàng đặt cược cộng đồng sẽ thích thử thách này, với ít tác động từ lần trước hoặc cảm giác "lặp đi lặp lại".
Mwr247

7
Mặc dù thử thách này rất giống với thử thách trước, nhưng tôi thực sự ủng hộ việc đóng lại thử thách trước như một bản sao của thử thách này. Thử thách này rõ ràng hơn và chất lượng cao hơn so với thử thách cũ.
Mego

Bạn có thể giải thích một chút về You cannot use built in change-of-base functions to convert the entire input string/number at once? Cụ thể, tôi có thể sử dụng tích hợp để chuyển đổi đầu vào thành cơ sở trung gian không? Sau đó tôi có thể sử dụng tích hợp để chuyển đổi sang cơ sở đích không? Sẽ như thế convert input with canonical form for given base; convert to base 10; convert to target base; convert back to specified character set with string replacementnào?
Mego

Câu trả lời:


5

CJam, 34 byte

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

Định dạng đầu vào là input_N alphabet input_B output_Bmỗi trên một dòng riêng biệt.

Chạy tất cả các trường hợp thử nghiệm.

Giải trình

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.

Điều này hoạt động cho cùng một số byte:

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

Sự khác biệt duy nhất là chúng tôi đang xây dựng một chuỗi thay vì thu thập mọi thứ trên ngăn xếp và đảo ngược nó.


7

Python 2 , 115 114 106 105 94 byte

Gợi ý chơi golf chào mừng. Hãy thử trực tuyến!

Chỉnh sửa: -9 byte nhờ mbomb007. -2 byte nhờ 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]

Ung dung:

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/=ttiết kiệm 9 byte.
mbomb007

Bạn có thể đặt z=0s=''trong khai báo hàm để lưu byte.
FlipTack

sử dụng printthay vì returnđược cho phép theo mặc định .
FlipTack

6

Nghiêm túc, 50 byte

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

Bãi rác Hex:

30bb2cbc2c32bf2c33bf2c34bfbe6034c0a1bd32c02a2bbb60
4d58bdeebb573b33c0402534c045bd402bbb33c0405c5758bd

Tôi tự hào về điều này mặc dù chiều dài của nó. Tại sao? Bởi vì nó hoạt động hoàn hảo trong lần thử thứ hai. Tôi đã viết nó và gỡ lỗi trong 10 phút. Thông thường gỡ lỗi một chương trình Nghiêm túc là một giờ lao động.

Giải trình:

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 (chức năng) với thư viện GMP , 260

Điều này hóa ra lâu hơn tôi mong đợi, nhưng đây là dù sao đi nữa. Các mpz_*công cụ thực sự ăn rất nhiều byte. Tôi đã thử #define M(x) mpz_##x, nhưng nó đã đạt được mức tăng 10 byte.

#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);}

Các chức năng F()là điểm vào. Nó chuyển đổi chuỗi đầu vào thành một mpz_tphép nhân liên tiếp theo cơ fromsở và thêm chỉ số của chữ số đã cho trong danh sách chữ số.

Hàm O()này là hàm đầu ra đệ quy. Mỗi đệ quy divmods mpz_tbởi to-base. Bởi vì điều này mang lại các chữ số đầu ra theo thứ tự ngược lại, đệ quy có hiệu quả cho phép các chữ số được lưu trữ trên ngăn xếp và đầu ra theo đúng thứ tự.

Lái thử:

Dòng mới và thụt lề thêm cho dễ đọc.

#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 byte

(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``

Không giống như mã của @ Mwr247 (sử dụng số học cơ sở f để chia s cho t mỗi lần, thu thập từng phần còn lại khi anh ta đi) Tôi sử dụng số học cơ sở để nhân câu trả lời cho f mỗi lần, thêm từng chữ số của s khi tôi đi.

Ung dung:

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

Ruby, 113 112 105 98 97 95 87 byte

Tôi sắp xếp hai câu trả lời Python của mình (bằng cách nào đó), vì vậy đây là câu trả lời của Ruby. Thêm bảy byte nhờ vào thao tác , một byte khác nhờ Martin Büttner và 8 byte nữa nhờ 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]}

Ung dung:

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

Làm thế nào về việc sử dụng s=d[z%t]+s;z/=tthay vì z,m=z.divmod t;s=d[m]+s?
cia_rana

3

APL, 10 byte

{⍺⍺[⍵⍵⍳⍵]}

Đây là một nhà điều hành APL. Trong APL, được sử dụng để truyền các giá trị, trong khi ⍵⍵⍺⍺thường được sử dụng để truyền các hàm. Tôi đang lạm dụng điều này ở đây để có 3 đối số. ⍺⍺là đối số bên trái, ⍵⍵là đối số bên phải "bên trong" và là đối số bên phải "bên ngoài".

Về cơ bản: ⍺(⍺⍺{...}⍵⍵)⍵

Sau đó, tất cả những gì cần thiết là tìm các vị trí của chuỗi đầu vào trong bảng "từ", sau đó sử dụng []để lập chỉ mục vào bảng "đến" với các vị trí này.

Thí dụ:

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

2

JavaScript (ES6), 175 byte

(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``')

Hình đã đủ dài để tôi có thể gửi cái tôi đã tạo để tạo các ví dụ. Tôi có thể thử và đánh golf xuống tốt hơn một chút sau đó.


Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.