实现真正的字符串添加


29

许多语言允许使用字符串“添加” +。但这确实是串联的,一个真正的加法将遵循组公理:

  • 它是封闭的(任何两个字符串的加总始终是一个字符串)

  • 它是关联的((a + b)+ c = a +(b + c)

  • 有一个恒等式(∃e:a + e = a

  • 每个元素都有一个逆数(∀a:∃b:a + b = e

(串联违反了第四组公理)

因此,我要执行的任务是实现真正的字符串加法,即该函数需要两个表示字符串的字节序列,然后返回第三个字节,以便您的函数满足字节序列上的所有组公理。

它必须适用于代表字符串的所有字节序列,包括具有空字节的字符串。

这是因此答案将以字节计分,而字节数越少越好。

Answers:


5

Python 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字节归功于notjagan

-33个字节,感谢Leaky Nun(和切换的字节序)

我没有任何尝试使用Python打高尔夫球的事情,但是我不想使用Lua,因为此方法需要大的精确整数来处理合理的长度st。(注意:增加字符串长度时,算法仍然非常慢。)这主要是为了提供答案;)

每个字符串都是自反的,空字符串是标识。这仅在字符串和非负整数之间的简单双射下执行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的(a)+α=(INV(A)+α)+ E =(INV(A)+α)+(INV(A)+ INV(INV的(a)))= inv(a)+(a + inv(a))+ inv(inv(a))=(inv(a)+ e)+ inv(inv(a))= inv(a)+ inv(inv(a) )= e

这也意味着ainv(a)的逆。

任何右身份都是左身份:e + a =(a + inv(a))+ a = a +(inv(a)+ a)= a

给定其他身份f,该身份是唯一的:e = e + f = f

如果a + x = a,x = ex = 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 )

遵循证明将使为不满足这些命题的拟议解决方案构造反例变得相当容易。

这是我在Lua中实现(但没有打高尔夫)的一种更自然的算法。也许会给别人一个主意。

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

这个想法基本上是根据长度的2的幂来分解字符串,然后将其视为字段,其中缺失的部分表示零,每个非缺失的部分表示从1到256 ^ n的数字,因此共有256 ^ n + 1个值。然后,可以将这些表示形式按分量模256 ^ n + 1相加。

注意:对于大小大于7的字符串,此Lua实现将出现数字溢出问题,但是长度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.

我想知道哪个esolangs具有内置的双射基本转换...
尼尔

那不应该以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''

在线尝试!通过对字符串进行异或运算,将其解释为小尾数双射基数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字符串的长度无关紧要。从字符串集到整数集存在双射映射。然后对整数值进行XOR运算,然后将映射取反。
尼尔

@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]

在线尝试!

将字符串转换为数字(按字符码减少),如果为奇数则取反,然后减半。不像其他人那样打高尔夫球,但是速度更快



1
n不是内射的,这会引起问题。例如n("\x00\x00")==n("\xff"),这失败了:print(f("\x00\x00","") == "\x00\x00")
tehtmi

:| 哦,不,这将是如此昂贵的修复
ASCII码,仅ASCII

1 or=>1or
扎卡里
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.