挑战相似度检测器


11

挑战

给定两个问题ID,尝试通过查看答案来找出它们的相似程度。

细节

系统将为您提供两个问题ID codegolf.stackexchange.com。您可能会认为两个ID都存在未删除但不一定打开的问题。您必须遍历所有答案,并确定两个问题的答案中的代码之间的最小Levenshtein距离(不包括已删除的答案)。也就是说,您应该将问题1中的每个答案与问题2中的每个答案进行比较,并确定最小Levenshtein距离。要在答案中找到代码,请执行以下过程:

如何找到代码片段

文本主体是答案的实际代码,如果该文本位于反引号中并且位于其自己的行上,或者如果它缩进了4个空格,并且在其上方有一个空行,除非上面没有文本。

有效和无效代码段(带.空格)的示例(以一等号分隔)

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

如果答案中没有有效的代码段,请完全忽略答案。请注意,您只应采用第一个代码块。

最终规格

可以以任何合理的格式输入2个整数的2个问题ID。输出应为任一挑战中任何两个有效答案之间的最小Levenshtein距离。如果没有一个或两个挑战的“有效”答案,请输出-1

测试用例

对于SparklePony同志的挑战115715(嵌入式六角形)和116616(嵌入式三角形),两个木炭答案(均由KritixiLithos提出)的Levenshtein距离为23,这是最小的。因此,你的输出115715, 11661623

编辑

您可能会因为API页面大小限制而假定该问题最多回答100个问题。仅当代码块本身是使用反引号创建的,而不是在其自己的行上创建时,才不应忽略代码块中的反引号。

编辑

我提早终止了赏金期限,因为我向国防部提出了要求将其悬停一星期的请求,而且我不希望将赏金自动授予得分最高的答案(碰巧是最长的)。如果有新的提交内容进入,或者提交的内容经过打高尔夫球,足以在赏金期限的实际结束之前(6月1日UTC 00:00)变得短于532字节,那么我将给予赏金以忠于我的诺言暂停到期。如果我没记错的话,下次我需要将赏金期限加倍,因此,如果您确实得到了答案,则可能会获得+200的收益:)


1
我对有效代码段感到困惑。为什么不只是html中<code>标记中的内容?
加尔文的业余爱好

@HelkaHomba换行限制如何?我可以尝试寻找另一种方式来合并这些内容。
HyperNeutrino

@HelkaHomba本质上,如果答案在一行中包含反引号分隔的代码,则应将其忽略。
HyperNeutrino

这是答案之一,在其中更容易解决问题的主要部分。下载页面和提取代码块比完成levenshtein距离要困难。
巴林特

1
凉。只是检查。
马特

Answers:


1

PowerShell,532字节

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

为了方便阅读,我在其中添加了换行符。仍然反映在我的字节数中。

可以肯定,我对此有把握。对我而言,最困难的部分实际上是获得Levenshtein距离,因为据我所知,PowerShell没有内置的距离。因此,我能够回答有关Levenshtein距离的挑战。当我的代码引用LD的匿名函数时,您可以参考该答案以获取有关其工作原理的更详细说明。

带有注释和进度指示器的代码

代码可能真的很慢(由于LD),所以我为自己建立了一些进度指示器,因此我可以按照动作进行操作,而不必假设它陷入某个地方的循环中。监视进度的代码不在顶层,也没有计入我的字节数。

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

查找代码块的逻辑是将答案作为HTML并寻找一个代码标签集,该标签集可选地由以其自己的行开始的pre标签集包围。在测试中,它在6个不同的问题集上找到了所有正确的数据。

我尝试使用降价代码工作,但是很难找到正确的代码块。

样品运行

Challenge-Similarity-Detector 97752 122740
57

Challenge-Similarity-Detector 115715 116616
23

我花了3天的大部分时间对此进行了研究。最有趣的尝试是,这项挑战在我的前5名中。TFTC(感谢挑战)
马特

不错的工作!谢谢,我很高兴您喜欢它!:)
HyperNeutrino

注意:我授予赏金的时间要早​​于声明的时间,因为我要申请暂停,因此以后再也不能授予。做得好!:)
HyperNeutrino's

要求暂停?
马特

是的,我请丹尼斯给我停赛1周的时间,这样我就可以专注于功课。之前已经完成了(尽管我还在这里……我不知道什么时候会消失)。
HyperNeutrino

3

Java + Jsoup,1027字节

前两个参数是问题ID。

打高尔夫球:

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()];}}

可读性:

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()];
}

}


击败我!!!真好!
tuskiomi

1
欢迎来到PPCG!使用第三方库并不违反规则,但是我们要求使用该语言来标注该库的使用(因此,使用名为JavaHTML的库的Java答案将被标记为“ Java + JavaHTML”)。
Mego

好,谢谢!下次我会记住这一点!
Tomahawk2001913

如果您愿意,没有什么可以阻止您在此挑战中使用库。
马特

我可能现在必须有人来回答我!
Tomahawk2001913

0

Mathematica,540个字节

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


输入

[“ 115715”,“ 116616”]

输出

23

使用内置的EditDistance,它“给出字符串或向量u和v之间的编辑距离或Levenshtein距离。”

至于测试用例mathematica

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

返回23

我想我可以
再打一些高尔夫,需要几分钟

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.