Rilevatore di somiglianze Challenge


11

Sfida

Dati due ID domanda, prova a capire quanto sono simili guardando le risposte.

Dettagli

Ti verranno dati due ID domanda per codegolf.stackexchange.com; si può presumere che esistano domande per entrambi gli ID che non sono stati eliminati, ma non sono necessariamente aperti. È necessario scorrere tutte le risposte e determinare la distanza minima di Levenshtein tra il codice nelle risposte alle due domande (escluse le risposte eliminate). Cioè, dovresti confrontare ogni risposta nella domanda 1 con ogni risposta nella domanda 2 e determinare la distanza minima di Levenshtein. Per trovare il codice in una risposta, assumere la seguente procedura:

Come trovare lo snippet di codice

Un corpo di testo è il codice effettivo della risposta se è in backtick ed è sulla sua stessa riga, o se è rientrato con 4 spazi, con una riga vuota sopra di esso, a meno che non ci sia testo sopra.

Esempi di frammenti di codice validi e non validi (con .come spazio) (separati da una tonnellata di segni uguali)

This is `not a valid code snippet because it is not on its own line`
========================================
This is:
`A valid code snippet`
========================================
This is
....not a valid code snippet because there's no spacing line above
========================================
This is

....A valid code snippet because there's a spacing line above
========================================
....Valid code snippet because there's no other text
========================================

Se non ci sono frammenti di codice validi nella risposta, ignora completamente la risposta. Nota che dovresti prendere solo il primo blocco di codice.

Specifiche finali

I due ID domanda possono essere inseriti in qualsiasi formato ragionevole per 2 numeri interi. L'output dovrebbe essere la minima distanza di Levenshtein tra due risposte valide per entrambe le sfide. Se non ci sono risposte "valide" per una o entrambe le sfide, produrre -1.

Caso di prova

Per la sfida 115715(Embedded Hexagons) e 116616(Embedded Triangles) entrambi del compagno SparklePony, le due risposte Charcoal (entrambe di KritixiLithos) avevano una distanza di Levenshtein di 23, che era la più piccola. Quindi, il tuo output per 115715, 116616sarebbe 23.

modificare

Si può presumere che la domanda abbia al massimo 100 risposte a causa di una limitazione del formato delle pagine API. Non si devono ignorare i backtick nei blocchi di codice, solo se il blocco di codice stesso viene creato usando i backtick e non sulla propria riga.

modificare

Ho interrotto anticipatamente il periodo di bounty perché avevo richiesto a un mod di ottenere una sospensione di una settimana e non volevo che il bounty fosse assegnato automaticamente alla risposta con il punteggio più alto (che sembra essere il più lungo). Se arriva un nuovo invio o se un invio viene lanciato abbastanza da diventare più breve di 532 byte prima della fine effettiva del periodo di ricompensa (UTC 00:00 il 1 ° giugno), darò una ricompensa per rimanere fedele alla mia promessa, dopo la sospensione scade. Se ricordo bene, dovrò raddoppiare il periodo di ricompensa la prossima volta, quindi se ricevi una risposta, potresti ottenere +200 :)


1
Sono confuso da ciò che conta come snippet di codice valido. Perché non qualsiasi cosa sia nei tag <code> nell'html?
Hobby di Calvin il

@HelkaHomba E le restrizioni di newline? Potrei provare a trovare un altro modo per incorporarli.
HyperNeutrino,

@HelkaHomba In sostanza, se la risposta contiene un codice delimitato da backtick all'interno di una riga, dovrebbe essere ignorato.
HyperNeutrino,

Questa è una di quelle risposte, dove è più facile fare la parte principale della domanda. Scaricare la pagina ed estrarre i blocchi di codice è più difficile che fare la distanza di levenshtein.
Bálint,

1
Freddo. Solo controllando.
Matt

Risposte:


1

PowerShell, 532 byte

$1,$2=$args
$a={irm "api.stackexchange.com/2.2/questions/$args/answers?pagesize=100&site=codegolf&filter=!9YdnSMKKT"|% i*}
$r={$args.body-replace"(?sm).*?^(<pre.*?>)?<code>(.*?)</code>.*",'$2'}
$1=&$a $1;$2=&$a $2
(0..($1.count-1)|%{
    $c=&$r $1[$_]
    0..($2.count-1)|%{
        &{$c,$d=$args;$e,$f=$c,$d|% le*;$m=[object[,]]::new($f+1,$e+1);0..$e|%{$m[0,$_]=$_};0..$f|%{$m[$_,0]=$_};1..$e|%{$i=$_;1..$f|%{$m[$_,$i]=(($m[($_-1),$i]+1),($m[$_,($i-1)]+1),($m[($_-1),($i-1)]+((1,0)[($c[($i-1)]-eq$d[($_-1)])]))|sort)[0]}};$m[$f,$e]} $c $d
    }
}|sort)[0]

Ho lasciato newline lì per un po 'di leggibilità. Si riflettono ancora nel mio conteggio byte.

Abbastanza sicuro di avere un controllo su questo. La parte difficile per me era in realtà ottenere la distanza di Levenshtein dal momento che PowerShell non ha una soluzione integrata per quel che ne so. Per questo motivo sono stato in grado di rispondere alla sfida correlata sulla distanza di Levenshtein . Quando il mio codice fa riferimento a una funzione anonima per LD, puoi fare riferimento a quella risposta per una spiegazione più dettagliata su come funziona.

Codice con commenti e indicatore di progresso

Il codice può diventare molto lento (a causa del LD), quindi ho inserito alcuni indicatori di progresso per me stesso in modo da poter seguire l'azione mentre si svolgeva e non dare per scontato che fosse bloccato in un circuito da qualche parte. Il codice per il monitoraggio dell'avanzamento non si trova nel blocco superiore né viene conteggiato nel mio conteggio byte.

# Assign the two integers into two variables. 
$1,$2=$args

# Quick function to download up to 100 of the answer object to a given question using the SE API
$a={irm "api.stackexchange.com/2.2/questions/$args/answers?pagesize=100&site=codegolf&filter=!9YdnSMKKT"|% i*}

# Quick function that takes the body (as HTML) of an answer and parses out the likely codeblock from it. 
$r={$args.body-replace"(?sm).*?^(<pre.*?>)?<code>(.*?)</code>.*",'$2'}

# Get the array of answers from the two questions linked.
$1=&$a $1;$2=&$a $2

# Hash table of parameters used for Write-Progress
# LD calcuations can be really slow on larger strings so I used this for testing so I knew 
# how much longer I needed to wait.
$parentProgressParameters = @{
    ID = 1 
    Activity = "Get LD of all questions" 
    Status = "Counting poppy seeds on the bagel"
}

$childProgressParameters = @{
    ID = 2
    ParentID = 1
    Status = "Progress"
}


# Cycle each code block from each answer against each answer in the other question.
(0..($1.count-1)|%{
    # Get the code block from this answer
    $c=&$r $1[$_]

    # Next line just for displaying progress. Not part of code. 
    Write-Progress @parentProgressParameters -PercentComplete (($_+1) / $1.count * 100) -CurrentOperation "Answer $($_+1) from question 1"

    0..($2.count-1)|%{
        # Get the code block from this answer   
        $d=&$r $2[$_]

        # Next two lines are for progress display. Not part of code. 
        $childProgressParameters.Activity = "Comparing answer $($_+1) of $($2.count)"
        Write-Progress @childProgressParameters -PercentComplete (($_+1) / $2.count * 100) -CurrentOperation "Answer $($_+1) from question 2"

        # Anonymous function to calculate Levenstien Distance
        # Get a better look at that function here: /codegolf//a/123389/52023
        &{$c,$d=$args;$e,$f=$c,$d|% le*;$m=[object[,]]::new($f+1,$e+1);0..$e|%{$m[0,$_]=$_};0..$f|%{$m[$_,0]=$_};1..$e|%{$i=$_;1..$f|%{$m[$_,$i]=(($m[($_-1),$i]+1),($m[$_,($i-1)]+1),($m[($_-1),($i-1)]+((1,0)[($c[($i-1)]-eq$d[($_-1)])]))|sort)[0]}};$m[$f,$e]} $c $d
    }
# Collect results and sort leaving the smallest number on top.
}|sort)[0]

La mia logica per trovare i blocchi di codice è prendere la risposta come HTML e cercare un set di tag di codice, facoltativamente circondato da un set di pre-tag che inizia su una propria riga. Nel test ha trovato tutti i dati corretti su 6 diversi set di domande.

Ho provato a lavorare dal codice markdown ma era troppo difficile trovare il blocco di codice giusto.

Esecuzioni campione

Challenge-Similarity-Detector 97752 122740
57

Challenge-Similarity-Detector 115715 116616
23

Ho trascorso la parte migliore di 3 giorni esaminando questo. Questa sfida è tra le mie 5 migliori per tentativi più divertenti. TFTC (Grazie per la sfida)
Matt

Bel lavoro! Grazie, sono contento che ti sia piaciuto! :)
HyperNeutrino

Nota: ho assegnato la taglia prima di quanto indicato perché sto richiedendo una sospensione, quindi non posso assegnarla in seguito. Buon lavoro! :)
HyperNeutrino

Richiesta di sospensione?
Matt,

Sì, ho chiesto a Dennis di concedermi una sospensione di 1 settimana per consentirmi di concentrarmi sui compiti scolastici. È già stato fatto prima (anche se sono ancora qui ... non so quando sparirò).
HyperNeutrino,

3

Java + Jsoup, 1027 byte

I primi due argomenti sono gli ID domanda.

golfed:

import org.jsoup.*;import org.jsoup.nodes.*;class M{String a1[]=new String[100],a2[]=new String[100],c[];int i1=0,i2=0;public static void main(String a[])throws Exception{String r="/codegolf/";M m=new M();m.c=m.a1;m.r(Jsoup.connect(r+a[0]).get());m.c=m.a2;m.r(Jsoup.connect(r+a[1]).get());int s=m.ld(m.a1[1],m.a2[1]);for(int i=2;i<m.a1.length;i++)for(int j=2;j<m.a2.length;i++){if(m.a1[i]==null)break;int d=m.ld(m.a1[i],m.a2[j]);if(d<s)s=d;}System.out.print(s);}void r(Document d){a:for(Element e:d.select("td")){for(Element p:e.select("pre")){ a(p.select("code").get(0).html());continue a;}}}void a(String d){c[c==a1?i1++:i2++]=d;}int ld(String a,String b){a=a.toLowerCase();b=b.toLowerCase();int[]costs=new int[b.length()+1];for(int j=0;j<costs.length;j++)costs[j]=j;for(int i=1;i<=a.length();i++){costs[0]=i;int nw=i-1;for(int j=1;j<=b.length();j++){int cj=Math.min(1+Math.min(costs[j],costs[j-1]),a.charAt(i-1)==b.charAt(j-1)?nw:nw+1);nw=costs[j];costs[j]=cj;}}return costs[b.length()];}}

Leggibile:

import org.jsoup.*;import org.jsoup.nodes.*;

class M {
    String a1[]=new String[100],a2[]=new String[100],c[];
    int i1=0,i2=0;
    public static void main(String a[])throws Exception{
    String r="/codegolf/";
    M m=new M();

    m.c=m.a1;
    m.r(Jsoup.connect(r+a[0]).get());
    m.c=m.a2;
    m.r(Jsoup.connect(r+a[1]).get());

    int s=m.ld(m.a1[1],m.a2[1]);
    for(int i=2;i<m.a1.length;i++)for(int j=2;j<m.a2.length;i++){if(m.a1[i]==null)break;int d=m.ld(m.a1[i],m.a2[j]);if(d<s)s=d;}
    System.out.print(s);
}

void r(Document d) {
    a:for(Element e:d.select("td")) {for(Element p:e.select("pre")) { 
        a(p.select("code").get(0).html());
        continue a;
    }}
}

void a(String d){c[c==a1?i1++:i2++]=d;}

int ld(String a, String b) {
    a = a.toLowerCase();
    b = b.toLowerCase();
    int [] costs = new int [b.length() + 1];
    for (int j = 0; j < costs.length; j++)costs[j] = j;
    for (int i = 1; i <= a.length(); i++) {
        costs[0] = i;
        int nw = i - 1;
        for (int j = 1; j <= b.length(); j++) {
            int cj = Math.min(1 + Math.min(costs[j], costs[j - 1]), a.charAt(i - 1) == b.charAt(j - 1) ? nw : nw + 1);
            nw = costs[j];
            costs[j] = cj;
        }
    }
    return costs[b.length()];
}

}


battermi ad esso !!!! Bello!
tuskiomi,

1
Benvenuti in PPCG! L'uso di una libreria di terze parti non è contrario alle regole, ma è necessario che l'uso della libreria venga annotato con il linguaggio (quindi una risposta Java che utilizza una libreria chiamata JavaHTML sarebbe etichettata "Java + JavaHTML").
Mego,

Ok grazie! Lo terrò a mente per la prossima volta!
Tomahawk2001913,

Non c'è nulla che ti impedisca di utilizzare una libreria in questa sfida se lo desideri.
Matt,

Potrei dover ora che qualcuno ha superato la mia risposta!
Tomahawk2001913,

0

Mathematica, 540 byte

f=Flatten;l=Length;P=StringPosition;(H[r_]:=Block[{s,a,t,k},t={};d=1;k="/codegolf/"<>r;s=First/@P[Import[k,"Text"],"<pre><code>"];a=f[First/@P[Import[k,"Text"],"answerCount"]][[1]];While[d<l@s,If[s[[d]]>a,AppendTo[t,s[[d]]]];d++];Table[StringDelete[StringCases[StringTake[Import[k,"Text"],{t[[i]],t[[i]]+200}],"<pre><code>"~~__~~"</code></pre>"],{"<pre><code>","</code></pre>"}],{i, l@t}]];Min@DeleteCases[f@Table[EditDistance[ToString@Row@H[#1][[i]],ToString@Row@H[#2][[j]]],{i,l@H[#1]},{j,l@H[#1]}],0])&


ingresso

["115715", "116616"]

produzione

23

usa EditDistance incorporato che "fornisce la modifica o la distanza di Levenshtein tra stringhe o vettori u e v".

Per quanto riguarda il caso di prova matematica

EditDistance["FN«AX²ιβ×__β↓↘β←↙β↑←×__β↖β→↗β","NαWα«X²ι↙AX²⁻ι¹β↙β↑↖β→A⁻α¹α"]

restituisce 23

Credo di poter golf un po 'più
prende qualche minuto per corsa

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.