Implementa l'aggiunta di stringhe vere


29

Molte lingue consentono di "aggiungere" stringhe con +. Comunque questa è davvero concatenazione, una vera aggiunta seguirà gli assiomi di gruppo:

  • È chiuso (l'aggiunta di due stringhe è sempre una stringa)

  • È associativo ( (a + b) + c = a + (b + c) )

  • C'è un'identità ( ∃e: a + e = a )

  • Ogni elemento ha un inverso ( ∀a: ∃b: a + b = e )

(la concatenazione viola l'assioma del 4 ° gruppo)

Quindi il mio compito per te è implementare una vera aggiunta di stringa, ovvero una funzione che accetta due sequenze di byte che rappresentano stringhe e ne restituisce un terzo in modo tale che la tua funzione soddisfi tutti gli assiomi di gruppo su sequenze di byte.

Deve funzionare su tutte le sequenze di byte che rappresentano le stringhe, comprese quelle con byte null.

Questo è quindi le risposte verranno classificate in byte con meno byte migliori.

Risposte:


5

Python 3 , 177 170 163 130 byte

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

Provalo online!

-14 byte grazie a notjagan

-33 byte grazie a Leaky Nun (e commutazione endianness)

Non ho intenzione di provare a giocare a golf su Python, ma non volevo usare Lua poiché questo metodo ha bisogno di numeri interi esatti di grandi dimensioni per funzionare con punture di lunghezza ragionevole. (Nota: l'algoritmo è ancora molto lento quando aumenta la lunghezza della stringa.) Questo è principalmente solo per fornire una risposta;)

Ogni stringa è auto-inversa e la stringa vuota è l'identità. Questo semplicemente esegue xor sotto una semplice biiezione tra stringhe e numeri interi non negativi. sè una funzione di supporto che calcola la biiezione (solo andata) ed dè l'inverso.

Versione non lenta (148 byte, per gentile concessione di 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

Provalo online!

Dirigerò questo anche per un primer di teoria dei gruppi.

Qualsiasi inverso destro è un inverso sinistro: inv (a) + a = (inv (a) + a) + e = (inv (a) + 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

Questo significa anche che a è un inverso di inv (a) .

Qualsiasi identità corretta è un'identità sinistra: e + a = (a + inv (a)) + a = a + (inv (a) + a) = a

L'identità è unica, data altra identità f : e = e + f = f

Se a + x = a allora x = e : x = e + x = (inv (a) + a) + x = inv (a) + (a + x) = inv (a) + a = e

Le inversioni sono univoche, se a + x = e quindi: x = e + x = (inv (a) + a) + x = inv (a) + (a + x) = inv (a) + e = inv (a )

Seguire le prove dovrebbe rendere abbastanza facile costruire controesempi per soluzioni proposte che non soddisfano queste proposizioni.

Ecco un algoritmo più naturale che ho implementato (ma non ho golf) in Lua . Forse darà un'idea a qualcuno.

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

L'idea è fondamentalmente di dividere la stringa in base alla potenza di due componenti della sua lunghezza e quindi di trattarli come campi con un componente mancante che rappresenta zero e ogni componente non mancante che rappresenta i numeri da 1 a 256 ^ n, quindi 256 ^ n + 1 valori totali. Quindi queste rappresentazioni possono essere aggiunte in base al componente modulo 256 ^ n + 1.

Nota: questa implementazione di Lua avrà problemi di overflow numerici per stringhe di dimensioni maggiori di 7. Ma l'insieme di stringhe di lunghezza 7 o inferiore è chiuso in questa aggiunta.

Provalo online!


Curiosità: poiché ogni elemento è il suo contrario, anche questo gruppo è abeliano.
Mago del grano

4

Gelatina , 8 byte

‘ḅ⁹^/ḃ⁹’

Questo utilizza una mappatura biiettiva φ dagli array di byte agli interi non negativi, XORs il risultato dell'applicazione di φ a due stringhe di input, quindi applica φ -1 al risultato.

L'array vuoto è l'elemento neutro e ogni array di byte è il proprio inverso.

Provalo online!

Come funziona

‘ḅ⁹^/ḃ⁹’  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.

Mi chiedevo quali esolang avessero incorporato la conversione di base biiettiva ...
Neil,

Non dovrebbe essere la base 257?
Tito

@Titus No, le cifre della base biiettiva 256 vanno da 1 a 256 (incluso).
Dennis,

Quindi ḅ⁹dalla base biiettiva 256 all'intero? Cosa A+Adà? chr(-1)?
Tito

@Titus Il processo di conversione da base a intero è identico per basi biiettive e "normali". [65] + [65]cederà [].
Dennis,

3

Python 2 , 114 byte

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''

Provalo online! Funziona con XORing le stringhe interpretate come base biiettiva little-endian 256.


d=lambda s:s>''and-~ord(s[0])+d(s[1:])*256salva tre byte; s=lambda d:d*'?'and chr(~-d%256)+s(~-d/256)ne salva ancora uno.
Lynn,

@Lynn Il secondo funzionerà per la grande d?
Neil,

Come funziona se le stringhe non hanno la stessa lunghezza?
Mago del grano

@WheatWizard La lunghezza delle stringhe è irrilevante. C'è una mappatura biiettiva dal set di stringhe al set di numeri interi. I valori interi vengono quindi XORati e la mappatura invertita.
Neil,

@Neil Ok grazie che vedo ora.
Mago del grano

1

Python 2 , 197 byte

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]

Provalo online!

Trasforma la stringa in un numero (riducendo di charcode), annulla se dispari, quindi dimezza. Non tanto golfoso come l'altro, ma più veloce: P



1
nnon è iniettivo, il che causa problemi. Ad esempio n("\x00\x00")==n("\xff"), ciò fallisce:print(f("\x00\x00","") == "\x00\x00")
tehtmi,

: | oh no che sarà così costoso da risolvere
solo ASCII il

1 or=>1or
Zacharý,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.