C# Damerau-Levenshtein距离,添加阈值

C# Damerau-Levenshtein距离,添加阈值,c#,levenshtein-distance,threshold,C#,Levenshtein Distance,Threshold,我有以下实现,但我想添加一个阈值,因此如果结果将大于它,只需停止计算并返回 我该怎么做呢 编辑:这是我的当前代码,threshold尚未使用…目标是使用它 public static int DamerauLevenshteinDistance(string string1, string string2, int threshold) { // Return trivial case - where they are equal if (stri

我有以下实现,但我想添加一个阈值,因此如果结果将大于它,只需停止计算并返回

我该怎么做呢

编辑:这是我的当前代码,
threshold
尚未使用…目标是使用它

    public static int DamerauLevenshteinDistance(string string1, string string2, int threshold)
    {
        // Return trivial case - where they are equal
        if (string1.Equals(string2))
            return 0;

        // Return trivial case - where one is empty
        if (String.IsNullOrEmpty(string1) || String.IsNullOrEmpty(string2))
            return (string1 ?? "").Length + (string2 ?? "").Length;


        // Ensure string2 (inner cycle) is longer
        if (string1.Length > string2.Length)
        {
            var tmp = string1;
            string1 = string2;
            string2 = tmp;
        }

        // Return trivial case - where string1 is contained within string2
        if (string2.Contains(string1))
            return string2.Length - string1.Length;

        var length1 = string1.Length;
        var length2 = string2.Length;

        var d = new int[length1 + 1, length2 + 1];

        for (var i = 0; i <= d.GetUpperBound(0); i++)
            d[i, 0] = i;

        for (var i = 0; i <= d.GetUpperBound(1); i++)
            d[0, i] = i;

        for (var i = 1; i <= d.GetUpperBound(0); i++)
        {
            for (var j = 1; j <= d.GetUpperBound(1); j++)
            {
                var cost = string1[i - 1] == string2[j - 1] ? 0 : 1;

                var del = d[i - 1, j] + 1;
                var ins = d[i, j - 1] + 1;
                var sub = d[i - 1, j - 1] + cost;

                d[i, j] = Math.Min(del, Math.Min(ins, sub));

                if (i > 1 && j > 1 && string1[i - 1] == string2[j - 2] && string1[i - 2] == string2[j - 1])
                    d[i, j] = Math.Min(d[i, j], d[i - 2, j - 2] + cost);
            }
        }

        return d[d.GetUpperBound(0), d.GetUpperBound(1)];
    }
}
公共静态int-dameraulevenshteInstance(字符串string1、字符串string2、int阈值)
{
//返回平凡的大小写-它们相等
if(string1.等于(string2))
返回0;
//返回小案例-其中一个为空
if(String.IsNullOrEmpty(string1)| | String.IsNullOrEmpty(string2))
返回(string1°).Length+(string2°).Length;
//确保string2(内部循环)更长
如果(string1.Length>string2.Length)
{
var tmp=string1;
string1=string2;
string2=tmp;
}
//返回普通情况-其中string1包含在string2中
if(string2.Contains(string1))
返回字符串2.长度-字符串1.长度;
var length1=string1.长度;
var length2=string2.长度;
变量d=新的整数[长度1+1,长度2+1];

对于(var i=0;i这是我能想到的最优雅的方法。在设置每个指数d后,看看它是否超过阈值。评估是恒定时间,因此与整个算法的理论N^2复杂度相比,它只是杯水车薪:

public static int DamerauLevenshteinDistance(string string1, string string2, int threshold)
{
    ...

    for (var i = 1; i <= d.GetUpperBound(0); i++)
    {
        for (var j = 1; j <= d.GetUpperBound(1); j++)
        {
            ...

            var temp = d[i,j] = Math.Min(del, Math.Min(ins, sub));

            if (i > 1 && j > 1 && string1[i - 1] == string2[j - 2] && string1[i - 2] == string2[j - 1])
                temp = d[i,j] = Math.Min(temp, d[i - 2, j - 2] + cost);

            //Does this value exceed your threshold? if so, get out now
            if(temp > threshold) 
              return temp;
        }
    }

    return d[d.GetUpperBound(0), d.GetUpperBound(1)];
}
公共静态int-dameraulevenshteInstance(字符串string1、字符串string2、int阈值)
{
...
对于(变量i=1;i 1&&string1[i-1]==string2[j-2]&&string1[i-2]==string2[j-1])
temp=d[i,j]=数学最小值(temp,d[i-2,j-2]+成本);
//这个值是否超过您的阈值?如果是,请立即离开
如果(温度>阈值)
返回温度;
}
}
返回d[d.GetUpperBound(0),d.GetUpperBound(1)];
}

终于得到了……尽管它并不像我希望的那样有益

    public static int DamerauLevenshteinDistance(string string1, string string2, int threshold)
    {
        // Return trivial case - where they are equal
        if (string1.Equals(string2))
            return 0;

        // Return trivial case - where one is empty
        if (String.IsNullOrEmpty(string1) || String.IsNullOrEmpty(string2))
            return (string1 ?? "").Length + (string2 ?? "").Length;


        // Ensure string2 (inner cycle) is longer
        if (string1.Length > string2.Length)
        {
            var tmp = string1;
            string1 = string2;
            string2 = tmp;
        }

        // Return trivial case - where string1 is contained within string2
        if (string2.Contains(string1))
            return string2.Length - string1.Length;

        var length1 = string1.Length;
        var length2 = string2.Length;

        var d = new int[length1 + 1, length2 + 1];

        for (var i = 0; i <= d.GetUpperBound(0); i++)
            d[i, 0] = i;

        for (var i = 0; i <= d.GetUpperBound(1); i++)
            d[0, i] = i;

        for (var i = 1; i <= d.GetUpperBound(0); i++)
        {
            var im1 = i - 1;
            var im2 = i - 2;
            var minDistance = threshold;

            for (var j = 1; j <= d.GetUpperBound(1); j++)
            {
                var jm1 = j - 1;
                var jm2 = j - 2;
                var cost = string1[im1] == string2[jm1] ? 0 : 1;

                var del = d[im1, j] + 1;
                var ins = d[i, jm1] + 1;
                var sub = d[im1, jm1] + cost;

                //Math.Min is slower than native code
                //d[i, j] = Math.Min(del, Math.Min(ins, sub));
                d[i, j] = del <= ins && del <= sub ? del : ins <= sub ? ins : sub;

                if (i > 1 && j > 1 && string1[im1] == string2[jm2] && string1[im2] == string2[jm1])
                    d[i, j] = Math.Min(d[i, j], d[im2, jm2] + cost);

                if (d[i, j] < minDistance)
                    minDistance = d[i, j];
            }

            if (minDistance > threshold)
                return int.MaxValue;
        }

        return d[d.GetUpperBound(0), d.GetUpperBound(1)] > threshold 
            ? int.MaxValue 
            : d[d.GetUpperBound(0), d.GetUpperBound(1)];
    }
公共静态int-dameraulevenshteInstance(字符串string1、字符串string2、int阈值)
{
//返回平凡的大小写-它们相等
if(string1.等于(string2))
返回0;
//返回小案例-其中一个为空
if(String.IsNullOrEmpty(string1)| | String.IsNullOrEmpty(string2))
返回(string1°).Length+(string2°).Length;
//确保string2(内部循环)更长
如果(string1.Length>string2.Length)
{
var tmp=string1;
string1=string2;
string2=tmp;
}
//返回普通情况-其中string1包含在string2中
if(string2.Contains(string1))
返回字符串2.长度-字符串1.长度;
var length1=string1.长度;
var length2=string2.长度;
变量d=新的整数[长度1+1,长度2+1];

对于(var i=0;i您也将此作为SQL CLR UDF问题提出,因此我将在特定上下文中回答:您最好的优化不是来自优化Levenshtein距离,而是来自减少比较的对数。是的,更快的Levenshtein算法将改善情况,但不如减少f的比较数量rom N square(数百万行中的N)到N*某个因子。我的建议是只比较长度差异在可容忍增量内的元素。在大表上,在
LEN(Data)
上添加一个持久化计算列,然后在其上创建包含数据的索引:

ALTER TABLE Table ADD LenData AS LEN(Data) PERSISTED;
CREATE INDEX ndxTableLenData on Table(LenData) INCLUDE (Data);
现在,如果数据的
LEN(data)
变化显著,您可以通过在长度上的最大差异(例如5)内加入来限制纯粹的问题空间:


这是关于你的回答: (抱歉,我还没有50个代表,无法发表评论)

我认为您在此处出错。您已初始化:

var minDistance = threshold;
您的更新规则是:

if (d[i, j] < minDistance)
   minDistance = d[i, j];

现在,请注意上面的if条件永远不会成立!您应该将
minDistance
初始化为
int.MaxValue

几乎!我调整了它以使其工作,
d[I,j]
由于某些原因,必须进行设置,所以我只是同时设置了temp,然后进行了检查,现在它工作得很好!谢谢!我错了,这不起作用…即使结果应该是1,如果我通过阈值2,结果是3。很容易看出为什么这不是非常有益的。您将minDistance设置为阈值d、 然后仅用较小的值替换它,然后测试MindDistance是否保持不变,或者是否随着字符串成本的计算而增长必须导致成本大于阈值,而且由于此算法永远不会减少其计算的成本,这是非常悲观的。据我所知,每个内部/
j
循环必须完成,否则结果将不正确。行中的最后一项是转换可以达到的最大距离。最小值为Is是当前可能的最小距离。这就是我跟踪每行的最小距离的原因,如果它已经超过阈值,则返回。它应该可以防止字符串中的几个外部/
I
循环出现大不相同的情况。此执行情况比我当前计算精确值的实现差,即使阈值非常低。我建议st改为使用stackoverflow.com/a/9454016/461444。它速度极快,似乎能给出准确的结果。我可以通过使用
soundex
连接我的表,然后应用levenshtein距离,从而显著提高性能。您还应该尝试添加一个持久列作为soundex,然后在(soundex)上添加索引对于包含(数据)。我同意减少比较次数更好;但是我已经将比较次数从1.2 exa减少到127.8 giga。现在我需要一个
if (d[i, j] < minDistance)
   minDistance = d[i, j];
if (minDistance > threshold)
   return int.MaxValue;