在具有1个字符差异的字符串列表中查找字符串

时间:2014-05-19 08:18:47

标签: c# linq string-comparison

在LINQ中是否可以在字符串列表中找到只有1个字符差异的字符串?

s_Str = "XXX_P_P1";
l_str = {"XXX_N_P1", "XX1_Z_P1","XX2_A_P1","DXX_P_P1"};
从上面

,结果应该返回:

f_Str = {"XXX_N_P1","DXX_P_P1"}

列表中的字符串将具有不同的字符串长度。我的主要要求是找到XXX_N_P1

主要要求各不相同,这就是为什么我只需找到1个字符差异的字符串。

5 个答案:

答案 0 :(得分:1)

您正在寻找名为edit distance的内容:

  

在计算机科学中,编辑距离是通过计算将一个字符串转换为另一个字符串所需的最小操作数量来量化两个字符串(例如,单词)彼此之间的差异的方法

一种流行的方法是例如使用Levenshtein distance

可以找到一个示例实现here,它会产生您正在寻找的结果。

var s_Str = "XXX_P_P1";

var l_str = new string[]{"XXX_N_P1", "XX1_Z_P1","XX2_A_P1","DXX_P_P1"};

var f_str = l_str.Where(l => LevenshteinDistance(s_Str, l) == 1).ToArray();

f_str现在是{"XXX_N_P1","DXX_P_P1"}


尽管如此,如果这太过分了,如果您正在寻找LINQ一行代码,那么您可以使用LINQ查询获得只有一个字符(忽略插入和删除)的所有字符串像这样:

l_str.Where(l => l.Zip(s_Str, (a, b) => a != b).Count(t => t) == 1);

答案 1 :(得分:1)

我们可以利用匿名对象的自动生成的相等和GetHashCode实现来连接表示字符位置的值对。我们期望结果集包含少一个字符串长度和源字符串长度相等的项。

var numMatches = str1
                  .Select((s,i) => new {s, i})
                  .Join(str2.Select((s, i) => new{s, i}), 
                                    a => a, 
                                    b => b, 
                                    (a, b) => 0) //what we select is unimportant
                  .Count(); //because we're only after a count

var singleCharIsDifferent=
                 (str1.Length == str2.Length)
                 && (str1.Length - 1) == numMatches;

答案 2 :(得分:0)

您需要LevenshteinDistance比较算法:

string s_Str = "XXX_P_P1";
var l_str = new List<string> { "XXX_N_P1", "XX1_Z_P1", "XX2_A_P1", "DXX_P_P1"};
var result = l_str.Where(x => LevenshteinDistance.Compute(s_Str, x) <= 1);


static class LevenshteinDistance
{
    /// <summary>
    /// Compute the distance between two strings.
    /// </summary>
    public static int Compute(string s, string t)
    {
        int n = s.Length;
        int m = t.Length;
        int[,] d = new int[n + 1, m + 1];

        // Step 1
        if (n == 0)
        {
            return m;
        }

        if (m == 0)
        {
            return n;
        }

        // Step 2
        for (int i = 0; i <= n; d[i, 0] = i++)
        {
        }

        for (int j = 0; j <= m; d[0, j] = j++)
        {
        }

        // Step 3
        for (int i = 1; i <= n; i++)
        {
            //Step 4
            for (int j = 1; j <= m; j++)
            {
                // Step 5
                int cost = (t[j - 1] == s[i - 1]) ? 0 : 1;

                // Step 6
                d[i, j] = Math.Min(
                    Math.Min(d[i - 1, j] + 1, d[i, j - 1] + 1),
                    d[i - 1, j - 1] + cost);
            }
        }
        // Step 7
        return d[n, m];
    }
}

答案 3 :(得分:0)

我之前用扩展方法解决了类似的问题:

/// <summary>
/// String extensions methods
/// </summary>
public static class StringExtensionsClass
{
    /// <summary>
    /// Check if two strings has only one "difference"
    /// </summary>
    /// <param name="BaseString"></param>
    /// <param name="StringToCountDiff"></param>
    /// <returns></returns>
    public static bool HasOneDiff(this string BaseString, string StringToCountDiff)
    {
        int _diffCount = 0;

        if (BaseString.Length == StringToCountDiff.Length)
        {
            for (int i = 0; i < BaseString.Length; i++)
            {
                if (BaseString[i] != StringToCountDiff[i])
                {
                    _diffCount++;
                }
            }

            if (_diffCount == 1)
            {
                return true;
            }
        }

        return false;
    }
}

和LINQ:

var matches = l_str.Where(l => l.HasOneDiff(s_Str) == true).ToArray();

答案 4 :(得分:-2)

我假设您想要比较由_分隔的标记。因此请使用String.Split('_')。然后,您可以使用Enumerable.Intersect来检查令牌匹配的数量。仅使用一个令牌最多不匹配的字符串:

var l_str = new List<string>{"XXX_N_P1", "XX1_Z_P1","XX2_A_P1","DXX_P_P1"};
string s_Str = "XXX_P_P1";
string[] findTokens = s_Str.Split('_');
List<string> f_Str = l_str
    .Select(str => new { str, split = str.Split('_') })
    .Where(x => x.split.Length - findTokens.Intersect(x.split).Count() >= x.split.Length - 1)
    .Select(x => x.str)
    .ToList();

结果:"XXX_N_P1","DXX_P_P1"