ASCII стиснення мистецтва від базового n числа


24

Це натхненне 05AB1E відповідь по Чарівній Octupus Чаші .

Дано два аргументи, додатне ціле число та рядок / список символів:

  1. Переведіть число на базовий-n, де n - довжина рядка.
  2. Для кожного символу замініть кожну появу індексу цього символу в базовому n номері цим символом.
  3. Роздрукуйте або поверніть новий рядок.

Приклади:

Input:
2740, ["|","_"]
2740 -> 101010110100 in base 2
     -> Replace 0s with "|" and 1s with "_"
Output: _|_|_|__|_||

Input:
698911, ["c","h","a","o"]
698911 ->  2222220133 in base 4
       ->  Replace 0s with "c", 1s with "h", 2s with "a", and 3s with "o"
Output -> "aaaaaachoo"

Input:
1928149325670647244912100789213626616560861130859431492905908574660758972167966, [" ","\n","|","_","-"]
Output:
    __   __    
   |  |_|  |   
___|       |___
-   -   -   -  
 - - - - - - - 
- - - - - - - -
_______________

Input: 3446503265645381015412, [':', '\n', '.', '_', '=', ' ', ')', '(', ',']
Output:
_===_
(.,.)
( : )
( : )

Правила:

  • IO гнучка .
    • Ви можете взяти число в будь-якій базі, якщо воно відповідає між введеннями
    • Список символів повинен бути 0-індексованим, хоча 0 - перший символ, а n-1 - останній
  • Можливими символами можуть бути будь-які друковані ASCII, а також пробіли, такі як вкладки та нові рядки
  • Даний список символів матиме довжину в діапазоні 2-10включно. Тобто найменша основа є двійковою, а найбільша - десятковою (тут немає набридливих літер )
  • Стандартні лазівки заборонені
  • Не соромтесь відповідати, навіть якщо ваша мова не може впоратися з більш широкими тестовими випадками.

Оскільки це , виграє найкоротший код для кожної мови. ( Я знаю, що всі мови з гольфу мають один байтовий вбудований модуль ;)


Пісочниця (видалено)
Jo King

3
Господи, я відчуваю себе шанованим. 05AB1E ascii-art був моїм улюбленим ще деякий час.
Чарівний восьминога Урна

ви можете створити новий виклик: знайдіть перестановку символів у масиві, щоб мінімізувати кількість :)
mazzy

Відповіді:


8

05AB1E , 7 6 байт

gв¹sèJ

Оскільки її надихнула відповідь 05AB1E, відповідь, подана в 05AB1E, здається придатною. :)

-1 байт завдяки @Enigma , видаливши припущення та зробивши це неявно.

Спробуйте в Інтернеті або перевірте всі тестові випадки .

Пояснення:

g         # `l`: Take the length of the first (string) input
 в        # And then take the second input in base `l`
          # For each digit `y` of this base-converted number:
  ¹sè     #  Push the `y`'th character of the first input
     J    # Join everything together (and output implicitly)

1
gв¹sèJщоб зберегти байт.
Емінья

@Emigna Дякую Не можу повірити, що я не думав про ¹sèсебе зараз .. (Я знав, що зміна ?на "A" Jдасть такий самий результат і в цьому випадку.)
Кевін Круїйсен

6

Java 8, 72 50 байт

a->n->n.toString(a.length).chars().map(c->a[c-48])

-22 байти завдяки @ OlivierGrégoire , повернувши IntStreamзамість цього друку безпосередньо.

Спробуйте в Інтернеті .

Пояснення:

a->n->                  // Method with char-array and BigInteger parameters
  n.toString(a.length)  //  Convert the input-number to Base `amount_of_characters`
   .chars()             //  Loop over it's digits (as characters)
   .map(c->a[c          //   Convert each character to the `i`'th character of the input
              -48])     //   by first converting the digit-character to index-integer `i`

2
a->n->n.toString(a.length).chars().map(c->a[c-48])(50 байт), оскільки "IO є гнучким"
Олів'є Грегоар,

String f(char[]a,int n){return n>0?f(a,n/a.length)+a[n%a.length]:"";}(69 байт) рекурсивний, для розваги.
Олів'є Грегоар

6

Python 3 , 49 байт

Поки ще не можна коментувати, тому я розміщую відповідь Python 2, адаптовану до Python 3.5.

f=lambda n,s:n and f(n//len(s),s)+s[n%len(s)]or''

2
Ласкаво просимо до PPCG! Не соромтеся включити посилання TIO, щоб допомогти продемонструвати ваше рішення.
Джо Кінг

5

Japt, 2 байти

Може приймати другий вхід як масив або рядок. Помилка останніх 2 тестових випадків, оскільки числа перевищують максимальне число JavaScript. Замініть sна, ìщоб вивести масив символів замість цього.

sV

Спробуй це


5

Haskell , 40 39 байт

0!_=[]
n!l=cycle l!!n:div n(length l)!l

Спробуйте в Інтернеті!

Оскільки Intтип Haskell обмежений 9223372036854775807, для більшої кількості це не вдається.

-1 байт завдяки Лайконі .

Безумовно

(!) :: Int -> [Char] -> [Char]

0 ! _ = []  -- If the number is 0, we reached the end. Base case: empty string
n ! l = 
  let newN = (n `div` length l) in   -- divide n by the base
    cycle l!!n                       -- return the char encoded by the LSD ... 
    : newN!l                         -- ... prepended to the rest of the output (computed recursively)

Спробуйте в Інтернеті!


Хороша ідея використовувати cycleзамість mod! div n(length l)зберігає байт.
Лайконі

4

MATL , 2 байти

YA

Спробуйте в Інтернеті!

Введення - це число і рядок.

Помилка для чисел, що перевищують 2^53через точність з плаваючою комою.

Пояснення

Що YAвідомо, вбудований (базове перетворення із заданими цільовими символами).


4

JavaScript (ES6), 48 байт

Приймає введення в синтаксис currying (c)(n), де c - список символів, а n - ціле число.

Безпечно лише для n <2 53 .

c=>n=>n.toString(c.length).replace(/./g,i=>c[i])

Спробуйте в Інтернеті!


JavaScript (ES6), 99 байт

З підтримкою великих цілих чисел

Приймає введення в синтаксис currying (c)(a), де c - список символів і a - список десяткових цифр (у вигляді цілих чисел).

c=>g=(a,p=0,b=c.length,r=0)=>1/a[p]?g(a.map((d,i)=>(r=d+r*10,d=r/b|0,r%=b,d|i-p||p++,d)),p)+c[r]:''

Спробуйте в Інтернеті!


4

32-бітний машинний код x86 (32-бітні цілі числа): 17 байт.

(також дивіться інші версії нижче, включаючи 16 байт для 32-розрядної або 64-бітової версії, з умовою виклику DF = 1.)

Caller передає аргументи в регістри, включаючи вказівник на кінець вихідного буфера (як моя відповідь C ; див. Це для обґрунтування та пояснення алгоритму.) Внутрішній glibc _itoaробить це , тому це не просто придумано для коду-гольфу. Регістри передачі аргументу близькі до системи x86-64 System V, за винятком того, що у нас є arg в EAX замість EDX.

Після повернення EDI вказує на перший байт 0-закінченого рядка C у вихідному буфері. Звичайний реєстр зворотних значень - це EAX / RAX, але мовою складання ви можете використовувати будь-яку умову виклику, зручну для функції. ( xchg eax,ediв кінці додасть 1 байт).

Абонент може вирахувати явну довжину, якщо хоче, від buffer_end - edi. Але я не думаю, що ми можемо виправдати пропущення термінатора, якщо функція насправді не повертає початкові + кінцеві покажчики або вказівник + довжина. Це дозволило б заощадити 3 байти в цій версії, але я не думаю, що це виправдано.

  • EAX = n = число для декодування. (Для idiv. Інші аргументи не є неявними операндами.)
  • EDI = кінець вихідного буфера (64-розрядна версія все ще використовується dec edi, тому повинна бути низькою 4GiB)
  • ESI / RSI = таблиця пошуку, відома також як LUT. не клобовані.
  • ECX = довжина таблиці = основа. не клобовані.

nasm -felf32 ascii-compress-base.asm -l /dev/stdout | cut -b -30,$((30+10))- (Відредагована вручну, щоб зменшити коментарі, нумерація рядків дивна.)

   32-bit: 17 bytes        ;  64-bit: 18 bytes
                           ; same source assembles as 32 or 64-bit
 3                         %ifidn __OUTPUT_FORMAT__, elf32
 5                         %define rdi edi
 6   address               %define rsi esi
11          machine        %endif
14          code           %define DEF(funcname) funcname: global funcname
16          bytes           
22                         ;;; returns: pointer in RDI to the start of a 0-terminated string
24                         ;;; clobbers:; EDX (tmp remainder)
25                         DEF(ascii_compress_nostring)
27 00000000 C60700             mov     BYTE [rdi], 0
28                         .loop:                    ; do{
29 00000003 99                 cdq                    ; 1 byte shorter than   xor edx,edx / div
30 00000004 F7F9               idiv    ecx            ; edx=n%B   eax=n/B
31                         
32 00000006 8A1416             mov     dl, [rsi + rdx]   ; dl = LUT[n%B]
33 00000009 4F                 dec     edi               ; --output  ; 2B in x86-64
34 0000000A 8817               mov     [rdi], dl         ; *output = dl
35                         
36 0000000C 85C0               test    eax,eax           ; div/idiv don't write flags in practice, and the manual says they're undefined.
37 0000000E 75F3               jnz     .loop         ; }while(n);
38                         
39 00000010 C3                 ret
           0x11 bytes = 17
40 00000011 11             .size: db $ - .start

Дивно, що найпростіша версія з обмеженнями швидкості / розміру є найменшою, але std/ cldкоштує 2 байти, яку слід використовувати stosbв порядку зменшення та все-таки дотримуватися загальної схеми виклику DF = 0. (І STOS декременти після зберігання, залишаючи вказівник, що вказує один байт занадто низько на виході з циклу, коштуючи нам додаткових байтів для обходу.)

Версії:

Я придумав 4 суттєво різні хитрості реалізації (використання простого movзавантаження / зберігання (вище), використання lea/ movsb(акуратного, але не оптимального), використання xchg/ xlatb/ stosb/ xchg, і того, хто входить у цикл із злому перекриття інструкцій. Дивіться код нижче) . Останній потребує контингенту 0в таблиці пошуку, щоб скопіювати його як термінатор вихідного рядка, тому я рахую це як 1 байт. Залежно від 32/64-бітових (1-байт incчи ні) та чи можемо ми вважати, що абонент встановлює DF = 1 ( stosbнизхідний) чи будь-що інше, різні версії є (прив'язаними для) найкоротшими.

DF = 1 для зберігання у порядку зменшення робить виграш xchg / stosb / xchg, але абонент часто цього не хоче; Це здається, що розвантажувати роботу абоненту важко виправданим чином. (На відміну від користувальницьких регістрів передачі аргументів та зворотних значень, які, як правило, не коштують абонента ASM зайвої роботи.) Але в 64-бітовому коді cld/ scasbпрацює як inc rdi, уникаючи обрізання вихідного вказівника на 32-бітний, тому іноді це незручно зберігати DF = 1 у 64-бітних чистих функціях. . (Покажчики статичного коду / даних є 32-бітними у x86-64 не-PIE-файлах у Linux та завжди в Linux x32 ABI, тому версія x86-64, що використовує 32-бітні покажчики, може використовуватися в деяких випадках.) У будь-якому випадку, ця взаємодія робить цікавим перегляд різних комбінацій вимог.

  • IA32 з коефіцієнтом DF = 0 на умові виклику входу / виходу: 17B ( nostring) .
  • IA32: 16B (з умовою DF = 1: stosb_edx_argабо skew) ; або з вхідним DF = dontcare, залишаючи його встановленим: 16 + 1Bstosb_decode_overlap або 17Bstosb_edx_arg
  • x86-64 з 64-бітовими вказівниками та DF = 0 на умові виклику входу / виходу: 17 + 1 байт ( stosb_decode_overlap) , 18B ( stosb_edx_argабо skew)
  • x86-64 з 64-бітовими вказівниками, інша обробка DF: 16B (DF = 1 skew) , 17B ( nostringпри DF = 1, використовуючи scasbзамість dec). 18B ( stosb_edx_argзбереження DF = 1 з 3-байтовим inc rdi).

    Або якщо ми дозволимо повернути вказівник на 1 байт перед рядком, 15B ( stosb_edx_argбез incкінця). Все готово знову зателефонувати та розгорнути ще одну рядок у буфер з іншою базою / таблицею ... Але це матиме більше сенсу, якби ми також не зберігали закінчення 0, і ви могли б помістити тіло функції всередину циклу, так що це справді окрема проблема.

  • x86-64 з 32-бітовим вихідним вказівником, DF = 0 умовою виклику: поліпшення порівняно з 64-бітовим вихідним вказівником, але 18B ( nostring) пов'язано зараз.

  • x86-64 з 32-бітовим вихідним вказівником: поліпшення в порівнянні з найкращими 64-бітовими версіями вказівника, так що 16B (DF = 1 skew). Або встановити DF = 1 і залишити його, 17B для skewз, stdале ні cld. Або 17 + 1B для stosb_decode_overlapз inc ediв кінці замість cld/ scasb.

З DF = 1 умовою виклику: 16 байт (IA32 або x86-64)

Потрібен DF = 1 на вході, залишає його встановленим. Навряд чи правдоподібно , принаймні на основі функції. Це те ж саме, що і у наведеній версії, але з xchg, щоб отримати залишок в / з АЛ до / після XLATB (пошук таблиці з R / EBX в якості бази) та STOSB ( *output-- = al).

З нормальним коефіцієнтомstdcldscasb DF = 0 на умові входу / виходу, / / версія має 18 байт для 32 та 64-бітного коду та є 64-бітною чистою (працює з 64-бітовим вихідним вказівником).

Зауважте, що вхідні аргументи знаходяться в різних регістрах, включаючи RBX для таблиці (для xlatb). Також зауважте, що цей цикл починається із збереження AL, і закінчується останнім символом, який ще не зберігався (звідси і movв кінці). Отже цикл "перекошений" відносно інших, звідси і назва.

                            ;DF=1 version.  Uncomment std/cld for DF=0
                            ;32-bit and 64-bit: 16B
157                         DEF(ascii_compress_skew)
158                         ;;; inputs
159                             ;; O in RDI = end of output buffer
160                             ;; I in RBX = lookup table  for xlatb
161                             ;; n in EDX = number to decode
162                             ;; B in ECX = length of table = modulus
163                         ;;; returns: pointer in RDI to the start of a 0-terminated string
164                         ;;; clobbers:; EDX=0, EAX=last char
165                         .start:
166                         ;    std
167 00000060 31C0               xor    eax,eax
168                         .loop:                    ; do{
169 00000062 AA                 stosb
170 00000063 92                 xchg    eax, edx
171                         
172 00000064 99                 cdq                    ; 1 byte shorter than   xor edx,edx / div
173 00000065 F7F9               idiv    ecx            ; edx=n%B   eax=n/B
174                         
175 00000067 92                 xchg    eax, edx       ; eax=n%B   edx=n/B
176 00000068 D7                 xlatb                  ; al = byte [rbx + al]
177                         
178 00000069 85D2               test    edx,edx
179 0000006B 75F5               jnz     .loop         ; }while(n = n/B);
180                         
181 0000006D 8807               mov     [rdi], al     ; stosb would move RDI away
182                         ;    cld
183 0000006F C3                 ret

184 00000070 10             .size: db $ - .start

Аналогічна версія, яка не перекошується, затіняє EDI / RDI, а потім виправляє її.

                            ; 32-bit DF=1: 16B    64-bit: 17B (or 18B for DF=0)
70                         DEF(ascii_compress_stosb_edx_arg)  ; x86-64 SysV arg passing, but returns in RDI
71                             ;; O in RDI = end of output buffer
72                             ;; I in RBX = lookup table  for xlatb
73                             ;; n in EDX = number to decode
74                             ;; B in ECX = length of table
75                         ;;; clobbers EAX,EDX, preserves DF
76                             ; 32-bit mode: a DF=1 convention would save 2B (use inc edi instead of cld/scasb)
77                             ; 32-bit mode: call-clobbered DF would save 1B (still need STD, but INC EDI saves 1)
79                         .start:
80 00000040 31C0               xor     eax,eax
81                         ;    std
82 00000042 AA                 stosb
83                         .loop:
84 00000043 92                 xchg    eax, edx
85 00000044 99                 cdq
86 00000045 F7F9               idiv    ecx            ; edx=n%B   eax=n/B
87                         
88 00000047 92                 xchg    eax, edx       ; eax=n%B   edx=n/B
89 00000048 D7                 xlatb                  ; al = byte [rbx + al]
90 00000049 AA                 stosb                  ; *output-- = al
91                         
92 0000004A 85D2               test    edx,edx
93 0000004C 75F5               jnz     .loop
94                         
95 0000004E 47                 inc    edi
96                             ;; cld
97                             ;; scasb          ; rdi++
98 0000004F C3                 ret
99 00000050 10             .size: db $ - .start
    16 bytes for the 32-bit DF=1 version

Я спробував альтернативну версію цього з lea esi, [rbx+rdx]/ movsbяк внутрішнього корпусу циклу. (RSI скидає кожну ітерацію, але зменшення RDI). Але він не може використовувати xor-zero / stos для термінатора, тому він на 1 байт більший. (І це не 64-бітний чистий для таблиці пошуку без префікса REX на LEA.)


LUT з явною довжиною та 0-термінатором: 16 + 1 байт (32-бітний)

Ця версія встановлює DF = 1 і залишає його таким чином. Я рахую додатковий потрібний байт LUT як частину загальної кількості байтів.

Класна хитрість тут - це те, що однакові байти декодують двома різними способами . Ми потрапляємо в середину циклу з залишком = база та коефіцієнт = вхідний номер, і копіюємо 0 термінатор на місце.

Уперше за допомогою функції перші 3 байти циклу споживаються як високі байти disp32 для LEA. Те, що LEA копіює базу (модуль) в EDX, idivвидає залишок для пізніших ітерацій.

Другим байтом idiv ebpє FD, що є кодом для stdінструкції, яку ця функція потребує для роботи. (Це було щасливим відкриттям. Я розглядав це divраніше, що відрізняє від idivвикористання /rбітів в ModRM. Другий байт div epbдекодує як cmc, що нешкідливо, але не допомагає. Але idiv ebpми можемо насправді видалити stdверхню частину функції.)

Зверніть увагу, що вхідні регістри знову є різницею: EBP для бази.

103                         DEF(ascii_compress_stosb_decode_overlap)
104                         ;;; inputs
105                             ;; n in EAX = number to decode
106                             ;; O in RDI = end of output buffer
107                             ;; I in RBX = lookup table, 0-terminated.  (first iter copies LUT[base] as output terminator)
108                             ;; B in EBP = base = length of table
109                         ;;; returns: pointer in RDI to the start of a 0-terminated string
110                         ;;; clobbers: EDX (=0), EAX,  DF
111                             ;; Or a DF=1 convention allows idiv ecx (STC).  Or we could put xchg after stos and not run IDIV's modRM
112                         .start:
117                             ;2nd byte of div ebx = repz.  edx=repnz.
118                             ;            div ebp = cmc.   ecx=int1 = icebp (hardware-debug trap)
119                             ;2nd byte of idiv ebp = std = 0xfd.  ecx=stc
125                         
126                             ;lea    edx, [dword 0 + ebp]
127 00000040 8D9500             db  0x8d, 0x95, 0   ; opcode, modrm, 0 for lea edx, [rbp+disp32].  low byte = 0 so DL = BPL+0 = base
128                             ; skips xchg, cdq, and idiv.
129                             ; decode starts with the 2nd byte of idiv ebp, which decodes as the STD we need
130                         .loop:
131 00000043 92                 xchg    eax, edx
132 00000044 99                 cdq
133 00000045 F7FD               idiv    ebp            ; edx=n%B   eax=n/B;
134                             ;; on loop entry, 2nd byte of idiv ebp runs as STD.  n in EAX, like after idiv.  base in edx (fake remainder)
135                         
136 00000047 92                 xchg    eax, edx       ; eax=n%B   edx=n/B
137 00000048 D7                 xlatb                  ; al = byte [rbx + al]
138                         .do_stos:
139 00000049 AA                 stosb                  ; *output-- = al
140                         
141 0000004A 85D2               test    edx,edx
142 0000004C 75F5               jnz     .loop
143                         
144                         %ifidn __OUTPUT_FORMAT__, elf32
145 0000004E 47                 inc     edi         ; saves a byte in 32-bit.  Makes DF call-clobbered instead of normal DF=0
146                         %else
147                             cld
148                             scasb          ; rdi++
149                         %endif
150                         
151 0000004F C3                 ret
152 00000050 10             .size: db $ - .start
153 00000051 01                     db 1   ; +1 because we require an extra LUT byte
       # 16+1 bytes for a 32-bit version.
       # 17+1 bytes for a 64-bit version that ends with DF=0

Цей прийом декодування, що перекривається, також може бути використаний cmp eax, imm32: для ефективного переходу вперед 4 байти потрібно лише 1 байт, лише прапори, що клобують. (Це жахливо для продуктивності на процесорах, які позначають межі інструкцій у кеші L1i, BTW.)

Але тут ми використовуємо 3 байти, щоб скопіювати регістр і перейти в цикл. Зазвичай це займе 2 + 2 (mov + jmp), і ми дозволимо нам стрибнути у цикл прямо перед STOS, а не перед XLATB. Але тоді нам знадобиться окрема ЗПСШ, і це було б не дуже цікаво.

Спробуйте в Інтернеті! (з _startабонентом, який використовує sys_writeрезультат)

Найкраще для налагодження запустити його під straceабо hexdump виводу, так що ви можете переконатися, чи є \0термінатор у потрібному місці тощо. Але ви можете бачити, що це справді працює і виробляти AAAAAACHOOна вклад

num  equ 698911
table:  db "CHAO"
%endif
    tablen equ $ - table
    db 0  ; "terminator" needed by ascii_compress_stosb_decode_overlap

(Власне xxAAAAAACHOO\0x\0\0..., тому, що ми скидаємо з 2-х байт раніше в буфер на фіксовану довжину. Отже, ми можемо побачити, що функція написала байти, які вона повинна була, і не наступила на жодні байти, яких вона не повинна мати. Стартовий вказівник, переданий функції, був другим xсимволом, який супроводжувався нулями.)


3

Желе , 4 байти

ṙ1ṃ@

Спробуйте в Інтернеті!

буквально є вбудованим для цього. Інші три байти припадають на одноосновну індексацію Jelly.


З цікавості, чому Jelly навіть має вбудовану " Базову декомпресію; перетворять х у базову довжину (у), а потім індексують у ". Це для дуже виняткових випадків, коли база, яку ви мураш перетворюєте, і довжина рядка / цілого числа / списку рівні? Коли я шукаю його, я можу знайти лише три відповіді, використовуючи його: 1 ; 2 ; 3 . Якийсь дивний вбудований у щоденний код-гольф виклики imo. : S
Кевін Круїйсен

3
@KevinCruijssen це дуже корисно, коли ви хочете, наприклад, конвертувати N в шістнадцятковий за допомогою шістнадцяткових літер замість списку чисел.
Містер Xcoder

@KevinCruijssen Це метод стиснення рядків. У першому прикладі бажаний рядок є “sspspdspdspfdspfdsp”, але “çƥ÷£ḟ’ṃ“spdf”¤ви заощадите шість байтів. Особливо корисно це для базових 250 номерів
Jelly


3

Деревне вугілля , 3 1 байт

θη

Спробуйте в Інтернеті!Посилання на багатослівну версію коду. Редагувати: збережено 2 байти завдяки лише @ ASCII. Попередня версія до додавання вбудованого, 8 байт:

⭆↨θLη§ηι

Спробуйте в Інтернеті! Посилання на багатослівну версію коду. Пояснення:

    η       Second input
   L        Length
  θ         First input
 ↨          Base convert to array
⭆           Map over values and join
      η     Second input
       ι    Current value
     §      Index into list
            Implicitly print result

Насправді це вже повинно працювати, але явно я знову заплутався> _>
лише для ASCII

Крім того, це фактично буде 1 байт : P (хоча він наразі зламаний, тому я не використовую масив чисел і рядків як аргументи) (також мені цікаво, як (не) корисний неявний ввід)
лише ASCII

@ ASCII-тільки Ви не маєте на увазі "1 байт" (див. Вихід -vl ;-) Також неявне введення здавалося б майже не марним у вугільному вугіллі, за винятком подібних проблем.
Ніл

1
@ ASCII Множинне "байти" замість однини "байт" - це те, що означає Ніл. ;) Що стосується вашої 1-байтної відповіді, чому перекреслена θη? Виглядає трохи заплутано tbh. Чому б просто не зняти його повністю і залишити ?
Kevin Cruijssen

1
@Nit Я повторно перевірив, і вбудований модуль був доданий до того, як було задано питання, але я не зрозумів, оскільки в ньому була помилка.
Ніл

3

D , 112 байт

import std.conv;C u(C,I)(I n,C b){C t;for(I l=b.length;n;n/=l)t=to!C(n%l)~t;foreach(ref c;t)c=b[c-48];return t;}

Спробуйте в Інтернеті!

Це відповідь відповіді C ++ HatsuPointerKun

Стиль виклику - це u(ulong(n), to!(char[])(b)), де nі bє аргументи зліва і справа

D конкретні речі

До жаль, нам потрібно імпортувати , std.convщоб робити якісь - або перетворення типів вище дуже базовим перетворенням типу.

Використання системи шаблонів golfy та надання функції необхідних типів (саме тому називати її не просто u(n,b) ), ми можемо скоротити входження char[]і ulongв 1байтах кожного, коли всередині й функцій.

D ініціалізує наші типи для нас, тому C t;це скороченняC t=cast(char[])([])

to!Cперетворює ціле число n%lв масив символів (використовуючи кодові точки) і ~є конкатенацією

foreach(ref c;t)це як for(... : ...)цикл C ++ , але трохи довше. refце як &, він трактується cяк копіюється посилання (тобто ми можемо змінювати t). На щастя, D підводить тип cбез будь-якого ключового слова, що позначає тип.



3

C ++, 150 144 байт, uint64вхід

-6 байт завдяки Захарі

#include<string>
using s=std::string;s u(uint64_t n,s b){s t;for(;n;n/=b.size())t=std::to_string(n%b.size())+t;for(auto&a:t)a=b[a-48];return t;}

Використання змінної для зберігання розміру збільшить кількість рахунків на 1

Для виклику функції:

u(2740, "|_")

Перше число, друге - рядок (масив char)

Тестові приклади:

std::cout << u(2740, "|_") << '\n' << u(698911, "chao") << '\n';
return 0;

1
3 байти, щоб відголитись: Вам не потрібно місця після #include, ви можете змінитись ;;на справедливий ;, а '0'можна просто48
Zacharý

1
Також цикл while може бути forциклом:for(;n;n/=b.size())t=std::to_string(n%b.size())+t;
Zacharý

@ceilingcat, я забув, що b.size()в цьому циклі не змінюється.
Zacharý

@ceilingcat Це призведе до збільшення рахунку на 1, замість того, щоб зменшити його
HatsuPointerKun

2

Гілочка, 66 байт

Створено macro те, що має бути importвідредаговано у шаблон.

{%macro d(n,c)%}{%for N in n|split%}{{c[N]}}{%endfor%}{%endmacro%}

Очікувані цінності:

Для перших аргументів ( n):

  • число
  • рядок

Для другого аргументу ( c):

  • Масив чисел
  • Масив рядків

Як користуватись:

  • Створити .twig файл
  • Додайте {% import 'file.twig' as uncompress %}
  • Виклик макросу uncompress.d()

Безголівки (нефункціональні):

{% macro d(numbers, chars) %}
    {% for number in numbers|split %}
        {{ chars[number] }}
    {% endfor %}
{% endmacro %}


Ви можете перевірити цей код на веб- сайті: https://twigfiddle.com/54a0i9


2

Pyth, 9 8 7 байт

s@LQjEl

Збережено байт завдяки hakr14 та ще одній подяці містеру Xcoder.
Спробуйте тут

Пояснення

s@LQjEl
    jElQ      Convert the second input (the number) to the appropriate base.
 @LQ          Look up each digit in the list of strings.
s             Add them all together.

Збережіть байт, замінивши m@Qdна@LQ
hakr14

Збережіть байт, замінивши vzна E.
Містер Xcoder

2

C89, підписаний обмеженим діапазоном int n, 64 53 байти

  • changelog: візьміть char **outі змініть його, замість того, щоб приймати та повертати achar *

Приймає число як an int, таблиця пошуку як масив + довжина.
Вихід записується в а char *outbuf. Caller передає (за посиланням) вказівник на кінець буфера. Функція змінює цей покажчик, щоб вказувати на перший байт рядка при поверненні.

g(n,I,B,O)char*I,**O;{for(**O=0;n;n/=B)*--*O=I[n%B];}

Це дійсно C89 і працює правильно навіть при ввімкненій оптимізації. тобто не залежить від gcc-O0 поведінки коли випадає з кінця недійсної функції або має інший UB.

Передача вказівника до кінця буфера - це нормально для оптимізованої функції int> string, наприклад внутрішньої_itoa функції glibc . Дивіться цю відповідь для детального пояснення розбиття цілого числа на цифри з циклом div / mod, як ми це робимо тут, в C, а також x86-64 asm. Якщо основа має потужність 2, ви можете переключити / маскувати, щоб спочатку дістати цифри MSD, але в іншому випадку єдиний хороший варіант - це найменш значущий перший (з модулем).

Спробуйте в Інтернеті! . Негольована версія:

/* int n = the number
 * int B = size of I = base
 * char I[] = input table
 * char **O = input/output arg passed by ref:
 *    on entry: pointer to the last byte of output buffer.
 *    on exit:  pointer to the first byte of the 0-terminated string in output buffer
 */
void ungolfed_g(n,I,B,O)char*I,**O;
{
    char *outpos = *O;     /* Golfed version uses *O everywhere we use outpos */
    *outpos = 0;           /* terminate the output string */
    for(;n;n/=B)
        *--outpos = I[n%B]; /* produce 1 char at a time, decrementing the output pointer */
    *O = outpos;
}

У цій версії явної довжини вхід є тим, char table[]що не потребує завершального 0 байта, тому що ми ніколи не трактуємо його як рядок. Це може бути анint table[] для всіх, хто нас хвилює. У C немає контейнерів, які знають власну довжину, тому вказівник + довжина - це звичайний спосіб передавати масив з розміром. Тому ми обираємо це, а не потрібно strlen.

Максимальний розмір буфера приблизно sizeof(int)*CHAR_BIT + 1, тому він малий і постійний час компіляції. (Ми використовуємо цей простір з базою = 2 і всіма бітами, встановленими 1.), наприклад, 33 байти для 32-бітових цілих чисел, включаючи 0термінатор.


C89, підписаний int, таблиця у вигляді рядка C неявної довжини, 65 байт

B;f(n,I,O)char*I,**O;{B=strlen(I);for(**O=0;n;n/=B)*--*O=I[n%B];}

Це те саме, але вхід є рядком неявної довжини, тому ми повинні самі знаходити довжину.


2

Bash + основні утиліти , 49 байт

dc -e`echo -en $2|wc -c`o$1p|tr -dc 0-9|tr 0-9 $2

Спробуйте в Інтернеті!

Коментарі / пояснення

Це приймає аргументи командного рядка як вхідні дані (число в базі 10, потім один рядок зі списком символів) і виводить у stdout. Спеціальні символи, такі як пробіл, новий рядок тощо, можуть бути введені в восьмеричні позначення (наприклад, \040для пробілу), або \nдля нового рядка, \tдля вкладки чи будь-якої іншої послідовності проходження, яка echo -eі trінтерпретує однаково.

Тут багато байтів для обробки спеціальних символів та великих тестових випадків. Якщо мені доведеться обробляти лише не страшні символи, а цифри невеликі (наприклад, перший тестовий випадок), це зробить наступні 24 байти:

dc -e${#2}o$1p|tr 0-9 $2

Це використовує розширення параметрів, ${#2}щоб отримати кількість символів у рядку, будує програму dc для базового перетворення, а потім надсилає перетворене число tr.

Це не буде обробляти нові рядки або пробіли чи вкладки, однак, щоб мати справу з послідовностями евакуації, не впливаючи на основу, я роблю підрахунок символів wc -cпісля інтерпретації епізодів echo -en. Це розширює програму до 38 байт:

dc -e`echo -en $2|wc -c`o$1p|tr 0-9 $2

На жаль, dc має дратівливу "особливість", коли якщо він виводить велику кількість, він буде обертати його рядком з косою + новою лінією, тому більші тестові випадки мають цей додатковий вихід. Щоб видалити його, я передаю висновок постійного струму, tr -dc 0-9щоб видалити нечислові символи. І ось ми.


Я збираюся запропонувати dc -e${#2}o$1p|tr 0-9 "$2"взяти дані буквально замість \ уникнулої форми, щоб він міг обробляти пробіли, але trне має можливості, наприклад, розглянути -як символ діапазону. Якщо вхід -не має в одному кінці рядка, він розривається. Можливо, ви можете скористатися sed "y/0123456789/$2/". Ні, мабуть, ні, GNU sedвимагає, щоб обидві аргументи yбули однакової довжини, і, здається, задихаються в новому рядку.
Пітер Кордес

2

APL (Dyalog Unicode) , 14 13 12 байт

⊢⌷⍨∘⊂⊥⍣¯1⍨∘≢

Спробуйте в Інтернеті!

Infix негласна функція; не вдається обробити найбільший тестовий випадок через представлення плаваючої точки.

Збережено 1 2 байти завдяки @ Adám!

13 байт додані для заголовків: ⎕IO←0: Я NDEX Про Rigin = 0 і ⎕FR←1287: Р loat Р epresentation = 128 біт. (Я забув, що це не стосується. )

Як?

⊢⌷⍨∘⊂⊥⍣¯1⍨∘≢    Tacit function, infix.
               Tally (number of elements in) the right argument.
         ⍨∘     Then swap the arguments of
     ⊥⍣¯1       Base conversion (to base ≢<r_arg>)
               Enclose (convert to an array)
  ⍨∘            Then swap the arguments of
               Index
               (Into) the right argument.


1

Полотно , 7 байт

L┬{╵⁸@p

Спробуйте тут!

Пряма реалізація:

L┬{╵⁸@p
L      get the length of the input (popping the item)
 ┬     base decode the other input
  {    for each number there
   ╵     increment
    ⁸@   in the 1st input get that numbered item
      p  and output that

Набір символів введення може бути також рядком, доки він не містить нового рядка, оскільки Canvas не має символу нової лінії та автоматично перетворює його на 2D-об'єкт.



1

SOGL V0.12 , 10 байт

l;A─{IaWp}

Спробуйте тут!

Досить довго, враховуючи, що ідея в значній мірі реалізована мовою: ось , введення

¶    __   __    ¶   |  |_|  |   ¶___|       |___¶-   -   -   -  ¶ - - - - - - - ¶- - - - - - - -¶_______________¶

видає стислий рядок за допомогою цього методу.



1

Стакс , 2 байти

:B

Запустіть і налагоджуйте його

:Bце інструкція в stax, яка робить це. Зазвичай він працює на "string" * замість масиву "string". Зрештою, це означає, що вихід - це масив одиночних масивів символів. Але висновок неявно згладжується.

* Stax насправді не має рядкового типу. Текст представлений цілими масивами кодових точок.


Так, я ніколи не помічав цієї команди ...
wastl

Є багато. Я одного разу додав інструкцію до stax, яка вже існувала, і я просто забула про неї. (масив не спадає?)
рекурсивний



1

C (gcc) , 110 байт

char s[99],S[99];i;f(x,_)char*_;{i=strlen(_);*s=*S=0;while(x)sprintf(S,"%c%s",_[x%i],s),strcpy(s,S),x/=i;x=s;}

Спробуйте в Інтернеті!

Опис:

char s[99],S[99];           // Two strings, s and S (capacity 99)
i;                          // A variable to store the length of the string
f(x,_)char*_;{              // f takes x and string _
    i=strlen(_);            // set i to the length of _
    *s=*S=0;                // empty s and S
    while(x)                // loop until x is zero
        sprintf(S,"%c%s",   // print into S a character, then a string
                _[x%i],s),  // character is the x%i'th character of _, the string is s
        strcpy(s,S),        // copy S into s
        x/=i;               // divide x by the length of the string (and loop)
    x=s;}                   // return the string in s

1
Якщо ви починаєте в кінці буфера і працюєте назад, то можете уникнути sprintf. Моя версія C становить 53 байти , при цьому вихідний буфер надається абонентом. Ви можете зробити його strcpyв кінці, якщо хочете скопіювати байти до початку буфера.
Пітер Кордес

Це геніально. Мені байдуже, чи це незручний формат вводу / виводу. Незручний введення / вивід - це претензія на славу! Молодці, я б рекомендував помістити це в повідомлення щодо C.
LambdaBeta

Опублікував відповідь на тему Поради щодо гольфу в C, де пояснюється та обґрунтовується техніка.
Пітер Кордес

1

CJam , 11 байт

liq_,@\b\f=

Спробуйте в Інтернеті! Вводиться як число, потім новий рядок, а потім символи в арт. ASCII.

Пояснення

li           e# Read the first line and convert it to an integer
  q_,        e# Read the rest of the input and push its length n
     @\b     e# Convert the number to its base-n equivalent, as an array of numbers
        \f=  e# Map over the array, taking each element's index from the string

Оскільки "IO є гнучким", я думаю, ви можете позбутися від liqпочатку, і це заощадить 3 байти!
Хром

1

JavaScript, 39 байт

Порт Родового рішення Python .

s=>g=n=>n?g(n/(l=s.length)|0)+s[n%l]:""

Спробуйте в Інтернеті


Працює лише nдо 64-бітових, правда? (У Python вбудовані цілі числа з довільною точністю, але числа JS природноdouble точні поплавці, які можна перетворити на цілі числа). Схоже, це не працює для великих тестових випадків у цьому запиті, наприклад, 1928149325670647244912100789213626616560861130859431492905908574660758972167966. О, але питання дозволяє відповісти так. Все-таки слід зазначити.
Пітер Кордес

1

SimpleTemplate , 86 байт

Ого, це був величезний виклик!

Це було важко через відсутність прямого доступу до конкретних індексів, коли індекс є змінною.
Помилка також зробила його довше, вимагаючи збереження значень всередині змінної.

{@setA argv.1}{@eachargv.0}{@setC C,"{@echoA.",_,"}"}{@calljoin intoC"",C}{@/}{@evalC}

Очікувані цінності:

Першим аргументом ( argv.0) може бути:

  • Ціле число
  • Рядок з цифрами
  • Масив цілих чисел

Другим аргументом ( argv.1) може бути:

  • Рядок
  • Масив

Як це працює?

Це працює так:

  • Цикли через число / рядок передані як перший аргумент
  • Встановлює змінну C як масив, що містить:
    • Попереднє значення C
    • Рядок "{@echoA."
    • Значення циклу
    • Рядок "}"
  • Приєднується до всього разом (використовуючи joinфункцію PHP )
    Це призводить, наприклад, до Cвмісту"{@echoA.0}{@echoA.1}..."
  • Оцінює результат C

Безголівки:

{@set args argv.1}
{@each argv.0 as number}
    {@set code code, "{@echo args.", number , "}"}
    {@call join into code "", code}
{@/}
{@eval code}

Ви можете спробувати цей код на: https://ideone.com/NEKl2q


Оптимальний результат

Якщо б не було помилок, це був би найкращий результат, враховуючи обмеження (77 байт):

{@eachargv.0}{@setC C,"{@echoargv.1.",_,"}"}{@calljoin intoC"",C}{@/}{@evalC}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.