在第一个列表中将保留顺序的两个列表相交

时间:2015-03-13 10:17:38

标签: c# arrays string linq

我遇到问题我甚至不知道在Google / Stack Overflow中搜索什么。 如果您觉得需要进一步解释,那么请评论。

基本上我想要交叉两个列表并返回与原始第一个字符串值的保留顺序的相似性。

示例:

我有两个字符串,我将其转换为CharArray。 我希望将这两个数组相交并返回相似的值,包含/与第一个字符串(s1)的顺序


正如您所看到的,第一个字符串包含 E15 (按特定顺序),秒数也是如此。

因此,这两个字符串将返回:{' E',' 1',' 5' }

string s1 = "E15QD(A)";
string s2 = "NHE15H";

我面临的问题是,如果我更换" s2"用:

string s2 = "NQE18H" // Will return {'Q', 'E', '1' }

我的操作将返回:{' Q',' E',' 1' }

结果:{' E',' 1'因为 Q 不遵循 1

的字母

目前我的操作不是最大的努力,因为我不知道在.NET中使用哪些方法才能做到这一点。

当前代码:

List<char> cA1 = s1.ToList();
List<char> cA2 = s2.ToList();

var result = cA1.Where(x => cA2.Contains(x)).ToList();

随意帮助我,正确方向的指针是可以接受的,也是一个完整的解决方案。

3 个答案:

答案 0 :(得分:2)

这是一个"longest common substring"问题。

您可以使用此扩展程序懒惰地获取所有子字符串:

public static class StringExtensions
{
    public static IEnumerable<string> GetSubstrings(this string str)
    {
        if (string.IsNullOrEmpty(str))
            throw new ArgumentException("str must not be null or empty", "str");

        for (int c = 0; c < str.Length - 1; c++)
        {
            for (int cc = 1; c + cc <= str.Length; cc++)
            {
                yield return str.Substring(c, cc);
            }
        }
    }
}

使用此LINQ查询,它易于阅读:

string longestIntersection = "E15QD(A)".GetSubstrings()
    .Intersect("NQE18H".GetSubstrings())
    .OrderByDescending(s => s.Length)
    .FirstOrDefault();  // E1

Enumerable.Intersect也非常有效,因为它使用了一套。需要注意的是:如果两个字符串都比另一个字符串大,那么首先使用它会更有效(就内存而言):

longString.GetSubstrings().Intersect(shortString.GetSubstrings())

答案 1 :(得分:1)

我认为应该这样做:

string similar = null;

for (int i = 0; i < s1.Length; i++)
{
    string s = s1.Substring(0, i + 1);

     if (s2.Contains(s))
     {
         similar = s;
     }
}

char[] result = similar.ToCharArray();

答案 2 :(得分:0)

@TimSchmelter在原帖的评论中提供了这个答案的链接。

public int LongestCommonSubstring(string str1, string str2, out string sequence)
    {
        sequence = string.Empty;
        if (String.IsNullOrEmpty(str1) || String.IsNullOrEmpty(str2))
            return 0;

        int[,] num = new int[str1.Length, str2.Length];
        int maxlen = 0;
        int lastSubsBegin = 0;
        StringBuilder sequenceBuilder = new StringBuilder();

        for (int i = 0; i < str1.Length; i++)
        {
            for (int j = 0; j < str2.Length; j++)
            {
                if (str1[i] != str2[j])
                    num[i, j] = 0;
                else
                {
                    if ((i == 0) || (j == 0))
                        num[i, j] = 1;
                    else
                        num[i, j] = 1 + num[i - 1, j - 1];

                    if (num[i, j] > maxlen)
                    {
                        maxlen = num[i, j];
                        int thisSubsBegin = i - num[i, j] + 1;
                        if (lastSubsBegin == thisSubsBegin)
                        {//if the current LCS is the same as the last time this block ran
                            sequenceBuilder.Append(str1[i]);
                        }
                        else //this block resets the string builder if a different LCS is found
                        {
                            lastSubsBegin = thisSubsBegin;
                            sequenceBuilder.Length = 0; //clear it
                            sequenceBuilder.Append(str1.Substring(lastSubsBegin, (i + 1) - lastSubsBegin));
                        }
                    }
                }
            }
        }
        sequence = sequenceBuilder.ToString();
        return maxlen;
    }