c# - 使用 LINQ 计算两个字符串之间的汉明距离

标签 c# linq

我需要帮助。我正在编写一个函数来比较字符串参数之间的汉明距离,这意味着您必须返回每个字符串中相同索引处的元素不相同的次数。

我已经设法用 for 循环完成该方法,但是使用这个 Linq 方法它只通过了 9 项测试中的 8 项。

我的初始循环:

public static int Distance(string firstStrand, string secondStrand)
{
    int count = 0;

    if(firstStrand.Length>secondStrand.Length || firstStrand.Length<secondStrand.Length){throw new ArgumentException();}
    else if(firstStrand.Length == 0 || secondStrand.Length == 0){count = 0;}
    else if(firstStrand == secondStrand){count = 0;}
    else
    {
        for(int i = 0; i < firstStrand.Length; i++)
        {
            if(firstStrand[i] != secondStrand[i])
            {
                count++;
            }
        }
    }


    return count;
}

我对 Linq 的尝试:

public static int Distance(string firstStrand, string secondStrand)
{
    int count = 0;

    if (firstStrand.Length > secondStrand.Length || firstStrand.Length < 
    secondStrand.Length) { throw new ArgumentException(); }
    if(firstStrand.Length == 0 && secondStrand.Length == 0) { count = 0; }
    else if (firstStrand == secondStrand) { count = 0; }
    else
    {

        var result = firstStrand.Zip(secondStrand, (c, b) => c != b);

        foreach (int value in result)
        {
            count++;
        }

    }
        return count;
}

测试文件:

[Fact]
public void Empty_strands()
{
    Assert.Equal(0, Hamming.Distance("", ""));
}

[Fact]
public void Single_letter_identical_strands()
{
    Assert.Equal(0, Hamming.Distance("A", "A"));
}

[Fact]
public void Single_letter_different_strands()
{
    Assert.Equal(1, Hamming.Distance("G", "T"));
}

[Fact]
public void Long_identical_strands()
{
    Assert.Equal(0, Hamming.Distance("GGACTGAAATCTG", "GGACTGAAATCTG"));
}

[Fact]
public void Long_different_strands()
{
    Assert.Equal(9, Hamming.Distance("GGACGGATTCTG", "AGGACGGATTCT"));
}

[Fact]
public void Disallow_first_strand_longer()
{
    Assert.Throws<ArgumentException>(() => Hamming.Distance("AATG", "AAA"));
}

[Fact]
public void Disallow_second_strand_longer()
{
    Assert.Throws<ArgumentException>(() => Hamming.Distance("ATA", "AGTG"));
}

[Fact]
public void Disallow_left_empty_strand()
{
    Assert.Throws<ArgumentException>(() => Hamming.Distance("", "G"));
}

[Fact]
public void Disallow_right_empty_strand()
{
    Assert.Throws<ArgumentException>(() => Hamming.Distance("G", ""));
}

希望大家指点一下。我对 Linq 还是很陌生。

最佳答案

您的实现存在的问题是,当您比较字符值时,您从不考虑比较的结果。您只需计算比较值的总长度,这将与输入字符串的长度相同。

您有 9 个测试用例,但即使在您的实现中存在这个严重缺陷,8 个仍然成功,因为:

  • 零长度字符串通常会导致计数为零
  • 相同的字符串将通过您的==优化计算字符串的长度
  • 涉及不同长度字符串的测试用例会抛出异常,所以永远不要关心计算的计数

只有一个测试用例以非平凡的方式实际执行比较代码,所以当然是失败的那个。

在我看来,您的方法更有效的实现方式如下所示:

public static int Distance(string firstStrand, string secondStrand)
{
    if (firstStrand.Length != secondStrand.Length) { throw new ArgumentException(); }

    return firstStrand.Zip(secondStrand, (c, b) => c != b).Count(f => f);
}

一些注意事项:

  • 多次比较 Length 属性没有意义。检查第一个长度是否小于第二个,然后检查它是否大于第二个,与检查它们是否不相等相同。一旦您满足了该要求,您就不需要检查两个长度来了解两个长度是否为零。
  • 也没有必要像您一样尝试优化特殊情况。要比较字符串是否相等,您无论如何都需要扫描两者。这种“优化”实际上会损害性能,至少对于某些类型的数据而言是这样,因为它会导致字符串的过度迭代。优化零长度的情况也没有用;在进行这种比较时,零长度字符串是您最不用担心的。保持代码简单更好。

关于c# - 使用 LINQ 计算两个字符串之间的汉明距离,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58086046/

相关文章:

c# - 使用 `ToArray` 方法复制数组

c# - IEnumerable<T> 是否替换了糟糕的设计?

c# - 使用 LINQ 解析亚马逊商城 XML

c# - LinqKit 嵌套调用 "LINQ to Entities does not recognize the method ' Invoke'"

c# - 当另一个 WinForm 关闭时如何使我的主 WinForm 更新?

c# - Asp.Net:Javascript 模态窗口

c# - 数组获得的最小值大于其他值

linq查询匿名类型无法转换为POCO对象

c# - 编写这样的代码是否有任何反模式名称?

java - 里氏替换和 SRP 原则违反 - 如何最好地构建这个场景?