Реалізуйте додавання справжнього рядка


29

Багато мов дозволяють додавати рядки за допомогою +. Однак це дійсно конкатенація, істинне доповнення слід за аксіомами групи:

  • Він закритий (додавання будь-яких двох рядків - це завжди рядок)

  • Це асоціативно ( (a + b) + c = a + (b + c) )

  • Існує ідентичність ( ∃e: a + e = a )

  • У кожного елемента є обернена ( ∀a: ∃b: a + b = e )

(конкатенація порушує аксіому 4-ї групи)

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

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

Це тому відповіді будуть набиратись у байтах, менша кількість байтів - краща.

Відповіді:


5

Пітон 3 , 177 170 163 130 байт

lambda a,b:s(d(a)^d(b))
def s(n,x=0,s=''):
 while n:n-=1;s+=chr(n%256);n>>=8
 return s
def d(n,c=0):
 while s(c)!=n:c+=1
 return c

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

-14 байт завдяки нежагану

-33 байти завдяки Leaky Nun (та переключеній витримці)

У мене немає жодного бізнесу, який намагався бити що-небудь у Python, але я не хотів використовувати Lua, оскільки цей метод потребує великих точних чисел для роботи над розумними довжинами. (Примітка: алгоритм все ще дуже повільний при нарощуванні довжини рядка.) Це здебільшого просто для надання відповіді;)

Кожна струна є самооберненою, а порожня рядок - тотожністю. Це просто виконує xor під простим біекцією між рядками та негативними цілими числами. s- це допоміжна функція, яка обчислює біекцію (лише в один бік), і dє зворотною.

Не повільна версія (148 байт, люб’язно надавши Leaky Nun):

lambda a,b:s(d(a)^d(b))
def s(n,x=0,s=''):
 while n:n-=1;s=chr(n%256)+s;n>>=8
 return s
def d(n,c=0):
 while n:c=c*256+ord(n[0])+1;n=n[1:]
 return c

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

Я збираюся викрасти це також для групової теорії.

Будь-яке право зворотної ліва зворотний: INV (а) + а = (INV (а) + а) + е = (INV (а) + а) + (INV (а) + INV (INV (а))) = inv (a) + (a + inv (a)) + inv (inv (a)) = (inv (a) + e) ​​+ inv (inv (a)) = inv (a) + inv (inv (a) ) = е

Це також означає, що a є зворотним інв (a) .

Будь-яка права ідентичність - це ліва ідентичність: e + a = (a + inv (a)) + a = a + (inv (a) + a) = a

Ідентичність унікальна, враховуючи іншу тотожність f : e = e + f = f

Якщо a + x = a, то x = e : x = e + x = (inv (a) + a) + x = inv (a) + (a + x) = inv (a) + a = e

Звороти унікальні, якщо a + x = e, тоді: x = e + x = (inv (a) + a) + x = inv (a) + (a + x) = inv (a) + e = inv (a )

Після доказів слід досить легко побудувати контрприклади для запропонованих рішень, які не задовольняють цих пропозицій.

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

function string_to_list(s)
  local list_val = {}
  local pow2 = 2 ^ (math.log(#s, 2) // 1) -- // 1 to round down
  local offset = 0
  list_val.p = pow2
  while pow2 > 0 do
    list_val[pow2] = 0
    if pow2 & #s ~= 0 then
      for k = 1, pow2 do
        list_val[pow2] = 256 * list_val[pow2] + s:byte(offset + k)
      end
      list_val[pow2] = list_val[pow2] + 1
      offset = offset + pow2
    end
    pow2 = pow2 // 2
  end
  return list_val
end

function list_to_string(list_val)
  local s = ""
  local pow2 = list_val.p
  while pow2 > 0 do
    if list_val[pow2] then
      local x = list_val[pow2] % (256 ^ pow2 + 1)
      if x ~= 0 then
        x = x - 1
        local part = ""
        for k = 1, pow2 do
          part = string.char(x % 256) .. part
          x = x // 256
        end
        s = s .. part
      end
    end
    pow2 = pow2 // 2
  end
  return s
end

function list_add(list_val1, list_val2)
  local result = {}
  local pow2 = math.max(list_val1.p, list_val2.p)
  result.p = pow2
  while pow2 > 0 do
    result[pow2] = (list_val1[pow2] or 0) + (list_val2[pow2] or 0)
    pow2 = pow2 // 2
  end
  return result
end

function string_add(s1, s2)
  return list_to_string(list_add(string_to_list(s1), string_to_list(s2)))
end

В основному ідея полягає в тому, щоб розділити рядок на основі потужності двох компонентів його довжини, а потім трактувати їх як поля з пропущеним компонентом, що представляє нуль, і кожен несутній компонент, що представляє числа від 1 до 256 ^ n, тому 256 ^ n + 1 значення всього. Тоді до цих уявлень може бути доданий компонентний модуль 256 ^ n + 1.

Примітка. Ця реалізація Lua матиме чисельні проблеми переповнення рядків розмірами більше 7. Але набір рядків довжиною 7 або менше закритий під цим доповненням.

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


Веселий факт: Оскільки кожен елемент є власним зворотним, ця група також є абелевою.
Пшеничний майстер

4

Желе , 8 байт

‘ḅ⁹^/ḃ⁹’

При цьому використовується бієктивне відображення φ від байтових масивів до невід’ємних цілих чисел, XOR - результат застосування φ до двох вхідних рядків, потім застосовується φ -1 до результату.

Порожній масив є нейтральним елементом, і кожен байтовий масив є власним оберненим.

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

Як це працює

‘ḅ⁹^/ḃ⁹’  Main link. Argument: [A, B] (pair of byte arrays)

‘         Increment all integers in A and B.
 ḅ⁹       Convert from base 256 to integer.
   ^/     XOR the resulting integers.
     ḃ⁹   Convert from integer to bijective base 256.
       ’  Subtract 1.

Мені було цікаво, які езоланги мали вбудовану біективну конверсію бази ...
Ніл

Хіба це не повинно бути базою 257?
Тит

@Titus Ні, цифри биективное базового 256 діапазону від 1 до 256 (включно).
Денніс

Тож ḅ⁹від біективної бази 256 до цілого числа? Що A+Aдає? chr(-1)?
Тит

@Titus Процес перетворення бази-до цілого числа ідентичний для біективної та "нормальної" баз. [65] + [65]дасть урожай [].
Денніс

3

Python 2 , 114 байт

lambda a,b:s(d(a)^d(b))
d=lambda s:s and d(s[1:])*256+ord(s[0])+1or 0
s=lambda d:d and chr(~-d%256)+s(~-d/256)or''

Спробуйте в Інтернеті! Твори XORing рядків інтерпретуються як бієктивна база 256.


d=lambda s:s>''and-~ord(s[0])+d(s[1:])*256зберігає три байти; s=lambda d:d*'?'and chr(~-d%256)+s(~-d/256)економить ще одного.
Лінн

@Lynn Це другий, який буде працювати для великих d?
Ніл

Як це працює, якщо струни не однакової довжини?
Пшеничний майстер

@WheatWizard Довжина струн не має значення. Існує бієктивне відображення від набору рядків до набору цілих чисел. Цілі значення знаходяться тоді XORed, а відображення змінюється на зворотному рівні.
Ніл

@Neil Добре спасибі, я бачу зараз.
Пшеничний майстер

1

Python 2 , 197 байт

def n(s):
 n=s and ord(s[0])+1 or 0
 for c in s[1:]:n=n*256+ord(c)
 return(-1)**n*n/2
def f(l,r,s=""):
 i=n(l)+n(r)
 i=abs(i*2+(i<=0))
 while i>257:s=chr(i%256)+s;i/=256
 return["",chr(i-1)+s][i>0]

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

Перетворює рядок у число (зменшення на charcode), заперечує якщо непарне, то половину. Не настільки гофрований, як інший, але швидший: P



1
nне є ін’єкційним, що спричиняє проблеми. Наприклад, n("\x00\x00")==n("\xff")це не вдається:print(f("\x00\x00","") == "\x00\x00")
tehmi

: | о ні, це не буде так дорого виправити
лише ASCII

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