真の文字列追加を実装する


29

多くの言語では、文字列をで「追加」できます+。しかし、これは本当に連結であり、真の追加はグループ公理に従います。

  • 閉じられています(2つの文字列の追加は常に文字列です)

  • 結合的です((a + b)+ c = a +(b + c)

  • アイデンティティがあります(∃e:a + e = a

  • すべての要素には逆があります(∀a:∃b:a + b = e

(連結は第4グループ公理に違反します)

したがって、あなたへの私のタスクは、真の文字列の追加を実装することです。これは、文字列を表す2つのバイトシーケンスを受け取り、バイトシーケンスのすべてのグループ公理を満たす関数を返す関数です。

nullバイトの文字列を含む文字列を表すすべてのバイトシーケンスで動作する必要があります。

これはので、回答はバイト単位でスコアリングされ、バイト数は少ない方が良いです。

回答:


5

Pythonの3177の 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

オンラインでお試しください!

notjaganのおかげで-14バイト

Leaky Nunのおかげで33バイト(およびエンディアンの切り替え)

Pythonでゴルフをしようとするビジネスはありませんが、Luaを使用したくありませんでした。この方法は、適切な長さの刺し傷で動作するために大きな正確な整数を必要とするからです。(注:文字列の長さを増加させるとき、アルゴリズムはまだ本当に遅いです。)これはほとんど答えを提供するためだけです;)

各文字列は自己反転型であり、空の文字列はIDです。これは、文字列と非負整数間の単純な全単射で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()+)+ E =(INV()+)+(INV()+ INV(INV()))= 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

もし+ X =次いで、X = EX = E + X =(INV()+)+ X = INV()+(+ X)= INV()+ 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を法として追加できます。

注:このLua実装では、サイズが7を超える文字列に対して数値オーバーフローの問題が発生しますが、この追加では長さ7以下の文字列のセットは閉じられます。

オンラインでお試しください!


楽しい事実:すべての要素はそれ自体が逆なので、このグループもアーベルです。
小麦ウィザード

4

ゼリー、8バイト

‘ḅ⁹^/ḃ⁹’

これは、バイト配列から非負の整数への全単射マッピングφを使用し、2つの入力文字列にφを適用した結果の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''

オンラインでお試しください!リトルエンディアン全単射の基数256として解釈される文字列をXORすることにより機能します。


d=lambda s:s>''and-~ord(s[0])+d(s[1:])*2563バイトを節約します。s=lambda d:d*'?'and chr(~-d%256)+s(~-d/256)もう一つ節約します。
リン

@Lynnその2番目は大きなdで動作しますか?
ニール

文字列が同じ長さでない場合、これはどのように機能しますか?
小麦ウィザード

@WheatWizard文字列の長さは関係ありません。文字列のセットから整数のセットへの全単射マッピングがあります。次に、整数値がXORされ、マッピングが逆になります。
ニール

@Neil OKありがとうございます。
小麦ウィザード

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]

オンラインでお試しください!

文字列を数字に変換し(文字コードで削減)、奇数の場合は否定し、半分にします。他のゴルフほどゴルフではありませんが、より高速です:P



1
n問題を引き起こす単射ではありません。たとえばn("\x00\x00")==n("\xff")、これは失敗しますprint(f("\x00\x00","") == "\x00\x00")
。– tehtmi

:| 修正に非常にコストがかかることになるだろうことはオハイオ州
ASCIIのみの

1 or=>1or
ザカリー
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.