Non mi piace il cambiamento!


19

Ingresso:

Due stringhe senza newline o spazi bianchi.

Produzione:

Entrambe le stringhe di input su righe separate, con spazi ove necessario per una delle due stringhe. Ed una terza linea con i personaggi A, R, Me , in rappresentanza aggiunto , rimosso , modificato , e invariato .

Aggiungiamo spazi alla stringa di input superiore o inferiore (se necessario). L'obiettivo di questa sfida è quello di produrre con il minor numero possibile di modifiche ( ARM), noto anche come distanza di Levenshtein .

Esempio:

Diciamo che le stringhe di input sono ABCDEFe AFBECD, quindi l'output sarebbe questo:

A B CDEF
AFBECD  
 A A  RR

Ecco alcuni altri possibili output non validi come esempio (e ce ne sono molti altri):

ABCDEF
AFBECD
 MMMMM

A BCDEF
AFBECD 
 A MMMR

AB CDEF
AFBECD 
 MAMMMR

ABC DEF
AFBECD 
 MMAMMR

ABC  DEF
AFBECD  
 MMAA RR

ABCDEF 
AFB ECD
 MMR MA

 AB CDEF   // This doesn't make much sense,
AFBECD     // but it's to show leading spaces are also allowed
AM A  RR

Nessuno di questi ha solo quattro modifiche, quindi A B CDEF\nAFBECD \n A A RRè solo un output valido per questa sfida.

Regole della sfida:

  • Puoi supporre che le stringhe di input non contengano nuove righe o spazi.
  • Le due stringhe di input possono avere lunghezze diverse.
  • Una delle due stringhe di input dovrebbe rimanere così com'è, ad eccezione degli spazi iniziali / finali opzionali.
  • Se le tue lingue non supportano nulla oltre a ASCII, puoi supporre che l'input contenga solo caratteri ASCII stampabili.
  • Il formato di input e output è flessibile. Puoi avere tre stringhe separate, una matrice di stringhe, una singola stringa con nuove righe, una matrice di caratteri 2D, ecc.
  • Ti è permesso usare qualcos'altro invece di ARM, ma indica ciò che hai usato (cioè 123, o abc., ecc.)
  • Se è possibile più di un output valido con la stessa quantità di modifiche ( ARM), è possibile scegliere se emettere uno dei possibili output o tutti.
  • Gli spazi iniziali e finali sono facoltativi:

    A B CDEF
    AFBECD
     A A  RR
    

    o

    "A B CDEF\nAFBECD\n A A  RR"
                     ^
                     Note there are no spaces here
    

Regole generali:

  • Questo è , quindi vince la risposta più breve in byte.
    Non lasciare che le lingue di code-golf ti scoraggino dal pubblicare risposte con lingue non codegolfing. Prova a trovare una risposta il più breve possibile per "qualsiasi" linguaggio di programmazione.
  • Per la tua risposta valgono regole standard , quindi puoi usare STDIN / STDOUT, funzioni / metodo con i parametri corretti, programmi completi. La tua chiamata.
  • Sono vietate le scappatoie predefinite .
  • Se possibile, aggiungi un link con un test per il tuo codice.
  • Inoltre, si prega di aggiungere una spiegazione, se necessario.

Casi test:

In: "ABCDEF" & "AFBECD"

Output (4 changes):
A B CDEF
AFBECD  
 A A  RR                  

In: "This_is_an_example_text" & "This_is_a_test_as_example"

Possible output (13 changes):
This_is_an       _example_text
This_is_a_test_as_example     
         MAAAAAAA        RRRRR

In: "AaAaABBbBBcCcCc" & "abcABCabcABC"

Possible output (10 changes):
AaAaABBbBBcCcCc
 abcABCab cABC 
R MM  MMMR MM R

In: "intf(){longr=java.util.concurrent.ThreadLocalRandom.current().nextLong(10000000000L);returnr>0?r%2:2;}" & "intf(){intr=(int)(Math.random()*10);returnr>0?r%2:2;}"

Possible output (60 changes):
intf(){longr=java.util.concurrent.ThreadLocalRandom.current().nextLong(10000000000L);returnr>0?r%2:2;}
intf(){i ntr=(      i    n      t)(M  ath.r   andom        ()*         10          );returnr>0?r%2:2;}
       MR M  MRRRRRR RRRR RRRRRR MMMRR MMMMRRR     RRRRRRRR  MRRRRRRRRR  RRRRRRRRRR 

In: "ABCDEF" & "XABCDF"

Output (2 changes):
 ABCDEF
XABCD F 
A    R 

In: "abC" & "ABC"

Output (2 changes):
abC
ABC
MM 


Se ci sono più arrangiamenti alla stessa distanza, è corretto emetterne solo uno?
AdmBorkBork,

@AdmBorkBork Sì, solo uno dei possibili output è effettivamente l'output previsto (anche se l'output di tutte le opzioni disponibili va bene). Chiarirò questo nelle regole della sfida.
Kevin Cruijssen,

@Arnauld Ho rimosso la regola relativa agli spazi iniziali, quindi gli spazi iniziali e finali sono sia opzionali che validi sulla linea non modificata. (Il che significa che l'ultimo caso di test nella tua risposta è completamente valido.)
Kevin Cruijssen,

1
@Ferrybig Ah ok, grazie per la spiegazione. Ma per quanto riguarda questa sfida, supportare semplicemente ASCII stampabile è già abbastanza. Se vuoi supportare di più, sii mio ospite. Ma fintanto che funziona per i casi di test dato, sto bene con un comportamento indefinito per i cluster di grafene costituiti da più di 1 carattere del genere. :)
Kevin Cruijssen,

Risposte:


5

Haskell , 192 181 174 161 158 150 147 143 158 1 byte

e@(a:r)&f@(b:s)=snd$maximum[([1|' '<-s!!2],s)|s<-z(z(:))[a:" R",' ':b:"A",a:b:last("M":[" "|a==b])][r&f,e&s,r&s]]
x&y=[x,y,"RA"!!(0^length x)<$x++y]
z=zipWith

Provalo online! Esempio di utilizzo: "ABCDEF" & "AFBECD". Restituisce un elenco di tre stringhe. Questa è un'estensione della mia soluzione ricorsiva alla normale domanda a distanza di Levenshtein .

Spiegazione:

Per calcolare le minime modifiche per ottenere da "xyz"a "yw", ci concentriamo sul primo carattere di entrambe le stringhe. Esistono tre possibilità:

  • Rimuovere: Goccia xdalla prima stringa e ricorsivamente calcolare le modifiche per ottenere da "yz"a "yw". Questo produce le tre linee ["yz","yw"," M"]. Aggiungi xal primo, uno spazio al secondo e Ral terzo. Noi abbiamo
    xyz
    yw
    RM
  • Aggiungi: rilascia ydalla seconda stringa e calcola "xyz" & "w", che restituisce il risultato ["xyz","w","MRR"]. Dobbiamo aggiungere uno spazio sulla prima riga, ysulla seconda e Asulla terza riga:
     xyz
    yw
    AMRR
  • Modificato / Invariato: Siamo in grado di combinare questi due casi perché entrambi richiedono di far cadere il primo carattere di entrambe le stringhe e calcolare le modifiche minime tra le altre stringhe: "yz" & "w". Al risultato ["yz","w","MR"], aggiungiamo xsu lui prima e ysulla seconda riga. Solo per l'ultima riga dobbiamo differenziare se i caratteri iniziali sono uguali. Se sono uguali, viene aggiunto uno spazio alla terza riga, altrimenti (come in questo caso perché x \= y) Mviene aggiunto un:
    xyz
    yw
    MMR

Di questi tre candidati, dobbiamo trovare quello con il minor numero di modifiche. Ciò equivale ad avere il maggior numero di spazi sulla terza riga. Pertanto convertiamo ciascun candidato s(un elenco di tre stringhe) in una tupla ([1|' '<-s!!2],s), dove sappare come secondo componente e il primo componente è un elenco con tanti elementi quanti sono gli spazi nella terza riga di s(a s!!2causa dell'indicizzazione 0). Come elemento di lista 1viene utilizzato, ma l'elemento reale è irrilevante purché sia ​​lo stesso per tutti i candidati.

Complessivamente, questo produce l'elenco delle tuple

[([1], ["xyz", "yw", "RM"]), ([], ["xyz", "yw", "AMRR"]), ([], ["xyz", " yw", "MMR"])]
Il build-in maximumseleziona l'elemento più grande di questo elenco, in cui le tuple vengono confrontate lessicograficamente, ovvero dal punto di vista dei componenti da sinistra a destra. Poiché [1]è maggiore di [], viene selezionata la prima tupla e sndrestituisce il secondo componente, ovvero l'elenco di linee, della tupla.


1 +15 byte per correggere un bug in cui A-cambia alla fine di una stringa verrebbe visualizzata come R-cambia


lol questo fa sì che lo script utente pensi che questo sia 1 byte
HyperNeutrino,

8

JavaScript (ES6), 413 ... 343 342 byte

Salvato 5 byte modificando gli indici del loop, come suggerito da @KevinCruijssen

Accetta input come 2 stringhe nella sintassi del curry. Restituisce un array di 3 stringhe.

b=>a=>{m=[];x=a.length;y=b.length;for(i=j=0,c=d='';i<=y;c+=R='R')m[i]=[[c,i++]];for(;j++<x;)m[i=0][j]=[d+=A='A',j];for(;i<y;i++)for(j=0;j<x;)[C]=m[[X,S]=m[i][j],[Y,I]=m[i+1][j],[Z,D]=m[i][++j],Q=[Z+R,D+1],i+1][j]=b[i]==a[j-1]?[X+' ',S]:S<I?D<S?Q:[X+'M',S+1]:D<I?Q:[Y+A,I+1];return[(g=s=>C.replace(/./g,c=>c==s?' ':b[i++],i=0))(A),g(R,b=a),C]}

Casi test

Meno golf

b => a => {
  m = []; x = a.length; y = b.length;

  // initialize the leftmost column and the topmost row
  for(i = j = 0, c = d = ''; i <= y; c += R = 'R')
    m[i] = [[c, i++]];
  for(; j++ < x;)
    m[i = 0][j] = [d += A = 'A', j];

  // walk through the Levenshtein matrix
  for(; i < y; i++)
    for(j = 0; j < x;)
      [C] = m[                                // C = current string, once updated
        [X, S] = m[i][j],                     // substitution
        [Y, I] = m[i + 1][j],                 // insertion
        [Z, D] = m[i][++j],                   // deletion
        Q = [Z + R, D + 1],                   // precomputed update for deletion
        i + 1
      ][j] =
        b[i] == a[j - 1] ?
          [X + ' ', S]                        // unchanged character
        :
          S < I ?
            D < S ? Q : [X + 'M', S + 1]      // deletion or substitution
          :
            D < I ? Q : [Y + A, I + 1];       // deletion or insertion

  return [
    // g = helper function to format the output strings by inserting spaces
    (g = s => C.replace(/./g, c => c == s ? ' ' : b[i++], i = 0))(A),
    g(R, b = a),

    // final modification string, picked from the last visited cell
    C
  ]
}

Esempio

Di seguito è la matrice iniziale per b = "pippo" e a = "ok" :

//                     'o'           'k'
[ [ [ '',    0 ], [ 'A',   1 ], [ 'AA',  2 ] ],
  [ [ 'R',   1 ],  (undefined),  (undefined) ],  // 'f'
  [ [ 'RR',  2 ],  (undefined),  (undefined) ],  // 'o'
  [ [ 'RRR', 3 ],  (undefined),  (undefined) ] ] // 'o'

ed ecco la matrice finale dopo tutte le iterazioni:

//                     'o'           'k'
[ [ [ '',    0 ], [ 'A',   1 ], [ 'AA',  2 ] ],
  [ [ 'R',   1 ], [ 'M',   1 ], [ 'MA',  2 ] ],  // 'f'
  [ [ 'RR',  2 ], [ 'R ',  1 ], [ 'R A', 2 ] ],  // 'o'
  [ [ 'RRR', 3 ], [ 'RR ', 2 ], [ 'R M', 2 ] ] ] // 'o'

La stringa di modifica finale insieme alla distanza di Levenshtein sono memorizzate nella cella in basso a destra.


Stessa modifica che ho suggerito di salvare 1 byte rispetto a -1 / + 1 di je xsi applica ancora alla tua ultima modifica: b=>a=>{m=[];x=a.length;y=b.length+1;for(i=y;i--;)m[i]=[[i,'R'.repeat(i)]];for(j=x+1;j--;)m[i=0][j]=[j,'A'.repeat(j)];for(;++i<y;)for(j=-1;++j<x;)R=m[S=(X=m[i-1][j])[0],I=(Y=m[i][j])[0],D=(Z=m[i-1][j+1])[0],Q=[D+1,Z[1]+'R'],i][j+1]=b[i-1]==a[j]?[S,X[1]+' ']:S<I?D<S?Q:[S+1,X[1]+'M']:D<I?Q:[I+1,Y[1]+'A'];return[(g=s=>R[1].replace(/./g,c=>c==s?' ':b[i++],i=0))('A'),g('R',b=a),R[1]]}:)
Kevin Cruijssen,

1
@KevinCruijssen Ho salvato 5 byte portando la tua idea un passo avanti. Grazie!
Arnauld,

4

Python 2 , 548 536 484 500 1 488 447 381 2 373 371 357 350 byte

s,t=input()
n,m=len(s),len(t)
r=range
L=[[(j,'RA'[i<1]*j)for j in r(i,m-~i)]for i in r(n+1)]
for i in r(n):
 for j in r(m):M,R=L[i][j:j+2];A=L[i+1][j];v,V=min(A,R,M);x=('AR'[v in R],'M_'[s[i]==t[j]])[v in M];_=M;X=eval(x)[1]+x;L[i+1][j+1]=v+(x<'_'),X
for i in r(len(X)):s=s[:i]+' '*('B'>X[i])+s[i:];t=t[:i]+' '*('R'==X[i])+t[i:]
print s+'\n'+t+'\n'+X

Provalo online!

Utilizza 'ARM_'invece di'ARM '

Funziona costruendo la matrice di Levenshtein e quindi attraversando all'indietro per trovare le operazioni . Ora costruisce la stringa operativa contemporaneamente alla matrice di Levenshtein, come nella risposta JS di Arnauld

1: più byte, poiché non funzionava se la prima stringa era un singolo carattere.

2: Passato alla creazione delle combinazioni nella matrice di Levenshtein.


+1 per aver
impiegato

Bella risposta! +1 da me. Dato che non ho mai programmato in Python, non posso davvero aiutarti con il golf, tranne una cosa: m+i+1può essere m-~i.
Kevin Cruijssen,

Puoi usare una scheda invece di doppi spazi alla linea 7.
Stephen,

È possibile arrivare a 463 byte riducendo il ciclo di wile su una riga:while i+j<n+m:v,A=(L[i]+[m,m])[j:j+2];R,M=(L[i+1]+[m,m])[j:j+2];d=min(A,R,M);q=M==d or(R==d)*2;r+=' '*(d==v==M)or'AMR'[q];i+=q>0;j+=q<2
ovs

1

Python 2 , 310 byte

from difflib import*
a,b=input()
U,j=[],' '
for g,s,t,x,y in SequenceMatcher(0,a,b).get_opcodes():
	g,Y,T=g[0],y-x,t-s
	z,A,B=Y-T,a[s:t],b[x:y]
	if'q'<g:U+=[A+z*j,B+j*-z,'M'*min(T,Y)+'A'*z+'R'*-z]
	if'e'==g:U+=[A,B,j*Y]
	if'i'==g:U+=[j*Y,B,'A'*Y]
	if'e'>g:U+=[A,j*T,'R'*T]
for e in[0,1,2]:print''.join(U[e::3])

Provalo online!

Usandolo si difflib.SequenceMatchercalcola un allineamento tra due stringhe


Questo sembra dare alcuni risultati errati per alcuni degli altri casi di test. Più particolare:"This_is_an_example_text","This_is_a_test_as_example"
Kevin Cruijssen,

@KevinCruijssen grazie, l'ho appena risolto ^ _ ^
mdahmoune,

Bello, gj! Ma umm .. purtroppo anche il terzo caso di test (e anche il quarto) è errato. Una delle due righe deve essere non modificata (ad eccezione degli spazi iniziali / finali). Entrambe le linee contengono attualmente spazi nel mezzo.
Kevin Cruijssen,

@KevinCruijssen grazie ancora, sto
risolvendolo

1

Mathematica, 250 256 259 384 byte

~ 0.00035 secondi per la custodia del codice java.

(i=o=p="";a=Array;r=StringLength;If[Length@#>0,g=#&@@#;h=#[[2]];u=r@g;v=r@h;i=i<>g;o=o<>h;w=Abs[v-u];k=a[" "&,w];If[u<v,i=i<>k,o=o<>k];p=p<>a["M"&,u~Min~v];p=p<>a[If[u>v,"R","A"]&,w],i=i<>#;o=o<>#;p=p<>a[" "&,r@#]]&/@SequenceAlignment[#,#2];{i,o,p})&

Uso: f["ABCDE", "ABCDF"]

Provalo online!

Il codice si basa su un fatto che SequenceAlignmentfunziona per impostazione predefinita su

Con l'impostazione predefinita SimilarityRules-> Automatic, ogni corrispondenza tra due elementi contribuisce 1 al punteggio di somiglianza totale, mentre ogni mancata corrispondenza, inserimento o eliminazione contribuisce -1.

Vale a dire, il punteggio viene calcolato M, Ae R, di conseguenza.

Esempio:

esempio


2
Hmm, non ho mai programmato in Mathemetica, ma non è possibile cambiare i="";o="";p="";per i="";o=i;p=i;ridurre 2 byte?
Kevin Cruijssen,

2
Che dire i=o=p=""?
DavidC,

@DavidC Sì, l'avevo capito e l'ho già cambiato. grazie comunque
Keyu Gan,

1

D , 351 345 byte

-6 byte grazie a KevinCruijssen

string f(string a,string b){import std.algorithm;string x,y,z;size_t i,j,k;foreach(c;levenshteinDistanceAndPath(a,b)[1]){final switch(c)with(EditOp){case none:x~=a[i++];y~=b[j++];z~=" ";break;case substitute:x~=a[i++];y~=b[j++];z~="M";break;case insert:x~=" ";y~=b[j++];z~="A";break;case remove:x~=a[i++];y~=" ";z~="R";}}return x~"\n"~y~"\n"~z;}

Provalo online!


Puoi golf sei byte rimuovendo l'ultimo break;. +1 però, la prima volta che vedo il linguaggio di programmazione D.
Kevin Cruijssen il
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.