Je n'aime pas le changement!


19

Contribution:

Deux chaînes sans sauts de ligne ni espaces.

Production:

Les deux chaînes d'entrée sur des lignes distinctes, avec des espaces si nécessaire pour l'une des deux chaînes. Et une troisième ligne avec les personnages A, R, Met , représentant ajouté , retiré , modifié , et sans changement .

Nous ajoutons des espaces à la chaîne d'entrée supérieure ou inférieure (si nécessaire). Le but de ce défi est de générer le moins de changements ( ARM) possible, également connu sous le nom de distance Levenshtein .

Exemple:

Disons que les chaînes d'entrée sont ABCDEFet AFBECD, alors la sortie serait la suivante:

A B CDEF
AFBECD  
 A A  RR

Voici quelques autres sorties invalides possibles comme exemple (et il y en a beaucoup plus):

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

Cependant, aucun de ceux-ci n'a que quatre changements, donc seule A B CDEF\nAFBECD \n A A RRune sortie valide pour ce défi.

Règles du défi:

  • Vous pouvez supposer que les chaînes d'entrée ne contiennent pas de nouvelles lignes ou d'espaces.
  • Les deux chaînes d'entrée peuvent être de longueurs différentes.
  • L'une des deux chaînes d'entrée doit rester telle quelle, à l'exception des espaces facultatifs de début / fin.
  • Si vos langues ne prennent pas en charge autre chose que l'ASCII, vous pouvez supposer que l'entrée ne contiendra que des caractères ASCII imprimables.
  • Le format d'entrée et de sortie est flexible. Vous pouvez avoir trois chaînes distinctes, un tableau de chaînes, une chaîne unique avec des nouvelles lignes, un tableau de caractères 2D, etc.
  • Vous êtes autorisé à utiliser autre chose à la place de ARM, mais indiquez ce que vous avez utilisé (par exemple 123, ou abc., etc.)
  • Si plusieurs sorties valides sont possibles avec le même nombre de modifications ( ARM), vous pouvez choisir de sortir l'une des sorties possibles ou toutes.
  • Les espaces de début et de fin sont facultatifs:

    A B CDEF
    AFBECD
     A A  RR
    

    ou

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

Règles générales:

  • C'est le , donc la réponse la plus courte en octets l'emporte.
    Ne laissez pas les langues de golf de code vous décourager de publier des réponses avec des langues autres que le golf de code. Essayez de trouver une réponse aussi courte que possible pour «n'importe quel» langage de programmation.
  • Des règles standard s'appliquent à votre réponse, vous êtes donc autorisé à utiliser STDIN / STDOUT, des fonctions / méthodes avec les paramètres appropriés, des programmes complets. Ton appel.
  • Les failles par défaut sont interdites.
  • Si possible, veuillez ajouter un lien avec un test pour votre code.
  • Veuillez également ajouter une explication si nécessaire.

Cas de 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 


S'il y a plusieurs arrangements qui sont à la même distance, est-il OK de n'en sortir qu'un seul?
AdmBorkBork

@AdmBorkBork Oui, une seule des sorties possibles est en effet la sortie prévue (bien que la sortie de toutes les options disponibles soit également très bien). Je vais clarifier cela dans les règles du défi.
Kevin Cruijssen du

@Arnauld J'ai supprimé la règle concernant les espaces de début, les espaces de début et de fin sont donc facultatifs et valides sur la ligne non modifiée. (Ce qui signifie que le dernier cas de test dans votre réponse est complètement valide.)
Kevin Cruijssen

1
@Ferrybig Ah ok, merci pour l'explication. Mais en ce qui concerne ce défi, il suffit déjà de prendre en charge l'ASCII imprimable. Si vous voulez soutenir plus, soyez mon invité. Mais tant que cela fonctionne pour les cas de test donnés, je suis d'accord avec un comportement non défini pour les grappes de graphène constituées de plus d'un caractère comme celui-ci. :)
Kevin Cruijssen

Réponses:


5

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

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

Essayez-le en ligne! Exemple d' utilisation: "ABCDEF" & "AFBECD". Renvoie une liste de trois chaînes. Ceci est une extension de ma solution récursive à la question de distance de Levenshtein ordinaire .

Explication:

Pour calculer les modifications minimales à obtenir de "xyz"à "yw", nous nous concentrons sur le premier caractère des deux chaînes. Il y a trois possibilités:

  • Retirer: Chute xde la première chaîne et récursive calculer les modifications pour obtenir de "yz"la "yw". Cela donne les trois lignes ["yz","yw"," M"]. Ajoutez xau premier, un espace au second et Rau troisième. On a
    xyz
    yw
    RM
  • Ajouter: supprimer yde la deuxième chaîne et calculer "xyz" & "w", ce qui renvoie le résultat ["xyz","w","MRR"]. Nous devons ajouter un espace sur la première ligne, yà la deuxième et Aà la troisième ligne:
     xyz
    yw
    AMRR
  • / Modifiés demeure inchangée: Nous pouvons combiner ces deux cas parce que les deux ont besoin de laisser tomber le premier caractère des deux chaînes et calculer les modifications minimales entre les cordes restantes: "yz" & "w". Au résultat ["yz","w","MR"], nous ajoutons xle premier et yle deuxième ligne. Seulement pour la dernière ligne, nous devons différencier si les caractères initiaux sont les mêmes. S'ils sont identiques, un espace est ajouté à la troisième ligne, sinon (comme dans ce cas parce que x \= y) un Mest ajouté:
    xyz
    yw
    MMR

À partir de ces trois candidats, nous devons trouver celui avec le moins de modifications. Cela équivaut à avoir le plus d'espaces sur la troisième ligne. Par conséquent, nous convertissons chaque candidat s(une liste de trois chaînes) en un tuple ([1|' '<-s!!2],s), oùs apparaît comme deuxième composant et le premier composant est une liste avec autant d'éléments qu'il y a d'espaces dans la troisième ligne de s(en s!!2raison de l'indexation 0). Comme l'élément de liste 1est utilisé, mais l'élément réel n'est pas pertinent tant qu'il est le même pour tous les candidats.

Au total, cela donne la liste des tuples

[([1], ["xyz", "yw", "RM"]), ([], ["xyz", "yw", "AMRR"]), ([], ["xyz", " yw "," MMR "])]
Le build-in maximumsélectionne le plus grand élément de cette liste, où les tuples sont comparés lexicographiquement, c'est-à-dire les composants de gauche à droite. Comme [1]est plus grand que [], le premier tuple est sélectionné et sndrenvoie le second composant, c'est-à-dire la liste des lignes, du tuple.


1 +15 octets pour corriger un bug où A-changes à la fin d'une chaîne serait affiché comme R-changes


lol cela fait penser au script utilisateur qu'il s'agit d'un octet
HyperNeutrino

8

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

Enregistré 5 octets en ajustant les indices de boucle, comme suggéré par @KevinCruijssen

Prend l'entrée comme 2 chaînes dans la syntaxe de curry. Renvoie un tableau de 3 chaînes.

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

Cas de test

Moins 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
  ]
}

Exemple

Voici la matrice initiale pour b = "foo" et a = "ok" :

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

et voici la matrice finale après toutes les itérations:

//                     '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 chaîne de modification finale ainsi que la distance Levenshtein sont stockées dans la cellule en bas à droite.


Même changement, j'ai suggéré d'enregistrer 1 octet concernant -1 / + 1 jet xs'applique toujours à votre dernière modification: 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 J'ai économisé 5 octets en poussant votre idée un peu plus loin. Merci!
Arnauld

4

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

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

Essayez-le en ligne!

Utilise 'ARM_'au lieu de'ARM '

Fonctionne en construisant la matrice Levenshtein, puis en reculant pour trouver les opérations . Construit maintenant la chaîne d'opération en même temps que la matrice Levenshtein, comme dans la réponse JS d'Arnauld

1: Plus d'octets, car cela ne fonctionnait pas si la première chaîne était un seul caractère.

2: Passé à la construction des combinaisons dans la matrice Levenshtein.


+1 pour avoir pris moins de 60 secondes pour des mots de 6 caractères comme ma tentative initiale (échouée) lol
HyperNeutrino

Bonne réponse! +1 de moi. Comme je n'ai jamais programmé en Python, je ne peux pas vraiment vous aider avec le golf, sauf pour une chose: m+i+1peut l'être m-~i.
Kevin Cruijssen

Vous pouvez utiliser une tabulation au lieu des espaces doubles sur la ligne 7.
Stephen

Vous pouvez atteindre 463 octets en réduisant la boucle wile à une seule ligne: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 octets

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

Essayez-le en ligne!

L'utilisation difflib.SequenceMatcherqui calcule un alignement entre deux chaînes


Cela semble donner des résultats incorrects pour certains des autres cas de test. Plus particulièrement:"This_is_an_example_text","This_is_a_test_as_example"
Kevin Cruijssen

@KevinCruijssen merci, je viens de le réparer ^ _ ^
mdahmoune

Bien, gj! Mais euh .. le troisième cas de test (et le quatrième aussi) est également incorrect malheureusement. L'une des deux lignes ne doit pas être modifiée (sauf pour les espaces de début / fin). Les deux lignes contiennent actuellement des espaces au milieu.
Kevin Cruijssen

@KevinCruijssen merci encore, je le
répare

1

Mathematica, 250 256 259 384 octets

~ 0,00035 secondes pour le cas du code 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})&

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

Essayez-le en ligne!

Le code est basé sur un fait qui SequenceAlignmentfonctionne par défaut sur

Avec le paramètre par défaut SimilarityRules-> Automatic, chaque correspondance entre deux éléments contribue 1 au score de similitude total, tandis que chaque décalage, insertion ou suppression contribue -1.

A savoir, le score est calculé par M, Aet R, en conséquence.

Exemple:

exemple


2
Hmm, je n'ai jamais programmé en Mathemetica, mais n'est-il pas possible de passer i="";o="";p="";à i="";o=i;p=i;pour réduire 2 octets?
Kevin Cruijssen

2
Et alors i=o=p=""?
DavidC

@DavidC Oui, je l'avais réalisé et je l'ai déjà changé. merci quand même
Keyu Gan

1

D , 351 345 octets

-6 octets merci à 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;}

Essayez-le en ligne!


Vous pouvez jouer au golf six octets en supprimant le dernier break;. +1 cependant, la première fois que je vois le langage de programmation D.
Kevin Cruijssen
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.