在C#中查找两个字符串之间共同的字符数量。

9
我正在寻找一种方法,该方法将获取两个字符串并返回它们共同拥有的字符数量,例如:
"G010"和"G1820A"应返回3,因为G、0和1字符都存在于两者中。
如果一个字符在两个字符串中重复出现,则应分别计算,如下所示:
"G12AA"和"GAA2"应返回4,因为G、A、A和2字符都存在于两者中。
需要帮助吗?到目前为止,谷歌搜索并没有提供太多帮助。

3
可能很经典,但是你到目前为止尝试了任何事情吗? - Soner Gönül
我有一个比较两个字符串相似性的方法,但是它是基于相同索引处的字符,然而这完全不同。 - Tommy
"G12AA"和"GA2"应该返回4?而"GA2"和"G12AA"也应该返回4? - Francesco Milani
9个回答

7
好的,那这样做的优点在于最大化懒惰求值并最小化字符串操作。
public int CommonChars(string left, string right)
{
    return left.GroupBy(c => c)
        .Join(
            right.GroupBy(c => c),
            g => g.Key,
            g => g.Key,
            (lg, rg) => lg.Zip(rg, (l, r) => l).Count())
        .Sum(); 
}

基本上,它将每一边按字符进行分组,然后找到在两侧都有组的字符。匹配的组成对地计算,直到其中一个用完为止。这些计数求和以产生结果。
对于任何两个序列,执行此操作通常很简单。请参见下面。
public static int CommomCount<T>(
        this IEnumerable<T> source,
        IEnumerable<T> sequence,
        IEqualityComparer<T> comparer = null)
{
    if (sequence == null)
    {
        return 0;
    }

    if (comparer == null)
    {
        comparer = EqualityComparer<T>.Default;
    }

    return source.GroupBy(t => t, comparer)
        .Join(
            sequence.GroupBy(t => t, comparer),
            g => g.Key,
            g => g.Key,
            (lg, rg) => lg.Zip(rg, (l, r) => l).Count(),
            comparer)
        .Sum();
}

您可以像这样使用它。

"G12AA".CommonCount("GAA2")

可选的comparer参数在需要忽略大小写或其他特殊处理时可能会很有用。
为了重复利用性,我倾向于删除Sum()并返回一个IEnumerable<T>,然后在调用中添加求和,像这样:
public static IEnumerable<T> Commom<T>(
        this IEnumerable<T> source,
        IEnumerable<T> sequence,
        IEqualityComparer<T> comparer = null)
{
    if (sequence == null)
    {
        return Enumerable.Empty<T>();
    }

    if (comparer == null)
    {
        comparer = EqualityComparer<T>.Default;
    }

    return source.GroupBy(t => t, comparer)
        .Join(
            sequence.GroupBy(t => t, comparer),
            g => g.Key,
            g => g.Key,
            (lg, rg) => lg.Zip(rg, (l, r) => l),
            comparer)
        .SelectMany(g => g);
}

所以你可以轻松地做到

Console.WriteLine(new string("G12AA".Common("GAA2").ToArray()));

或者只是原始的。
"G12AA".Common("GAA2").Count();

4

试试这个

    public int CommonCharacters(string s1, string s2)
    {
        bool[] matchedFlag = new bool[s2.Length];

        for (int i1 = 0; i1 < s1.Length; i1++)
        {
            for (int i2 = 0; i2 < s2.Length; i2++)
            {
                if (!matchedFlag[i2] && s1.ToCharArray()[i1] == s2.ToCharArray()[i2])
                {
                    matchedFlag[i2] = true;
                    break;
                }
            }
        }

        return matchedFlag.Count(u => u);
    }

1
将条件语句中的顺序反转以提高效率:如果标志不会被使用,那么没有必要将所有额外的工作都用于将字符串更改为数组! - Nathan
1
我是指改变条件的顺序:if (s1[i1] == s2[i2] && !matchedFlag[i2]):先检查布尔值更有效率:改为if (!matchedFlag[i2] && s1[i1] == s2[i2]) - 见“短路” :) (现在你已经正确地在第一个条件上使用了字符串索引器,这样做会有多大的差异还有待商榷 - 必须是一个非常大的数据集 - 但我总是强调将最简单的条件放在使用&&的if语句的开头:可以产生实质性的差异,特别是在多个循环内部) - Nathan
呵呵,别担心 - 现在去掉tochararray调用 - 它们也是多余的 ;) - Nathan
好的,抱歉 - 我在测试代码中可能混淆了输入 - 我想我也有点困了 :) - Nathan
更好的是 - 不是混乱的输入,而是混乱的输出 - 复制粘贴失败了 哈哈string a = "G12A"; string b = "GAA2";var result = a.CommonCount(b); Console.WriteLine("mine: " + result); var result2 = StringExtensions.CommonCharacters(a, b); Console.WriteLine("other: " + result); - Nathan
显示剩余2条评论

1
您可以使用Linq来解决这个问题,例如使用以下代码:
static void Main(string[] args)
{
    IEnumerable<char> a = "G010".ToCharArray();
    IEnumerable<char> b = "G1820A".ToCharArray();

    int commonChars = FindCommonElements(a, b).Count();
    Console.WriteLine(commonChars);

    Console.ReadLine();
}

private static T[] FindCommonElements<T>(IEnumerable<T> source, IEnumerable<T> target)
{
    ILookup<T, T> lookup2 = target.ToLookup(i => i);

    return (
      from group1 in source.GroupBy(i => i)
      let group2 = lookup2[group1.Key]
      from i in (group1.Count() < group2.Count() ? group1 : group2)
      select i
    ).ToArray();
}

commonChars的值将为3。FindCommonElements方法的灵感来自于这个问题:如何在保留重复项的情况下进行整数列表交集?


你可以使用 Zip,如我在答案中所示,避免完全计算两个组。https://dev59.com/hHzaa4cB1Zd3GeqPQHJU#21751976 - Jodrell

1
        string s1 = "G12A";
        string s2 = "GAA2";
        List<char> lst1 = s1.ToList();
        List<char> lst2 = s2.ToList();
        int count = 0;
        foreach (char c in lst2)
        {
            if (lst1.Contains(c))
            {
                lst1.Remove(c);
                count++;
            }
        }
        Console.WriteLine(count);

你用 string s1 = "G12A"; 得到什么? - L.B
当s2 =“GAA2”时,如果s1中存在所有4个字符,则4是错误的吗? - Amit
@Amit 但是它们都只有一个共同的“A”,而不是两个。请参考Tommy的第一个例子。 - L.B
感谢 @L.B 提供了重复字符的场景说明。 - Amit

1
使用Linq完成它:
    int MyCount(string s1, string s2)
    {
        return s1.Count(c =>
                            {
                                var i = s2.IndexOf(c);
                                if (i >= 0)
                                {
                                    s2 = s2.Remove(i, 1);
                                    return true;
                                }
                                return false;
                            });
    }

0
string myname = "1234";
        string yourname = "12";
        char[] sam = new char[] { };
        sam = myname.ToCharArray();
        char[] sam1 = new char[] { };
        sam1 = yourname.ToCharArray();
        int id = 0;
        int id1 = 0;
        List<string> found = new List<string>();
        List<string> found1 = new List<string>();
        foreach (char item in sam)
        {
            if (found.Contains(item.ToString()))
            {
                found.Add(item.ToString() + id);
                id++;
            }
            else
                found.Add(item.ToString());
        }
        foreach (var item in sam1)
        {
            if (found1.Contains(item.ToString()))
            {
                found1.Add(item.ToString() + id);
                id1++;
            }
            else
                found1.Add(item.ToString());
        }
        var final = found.Except(found1);
        var final2 = found1.Except(found);
        var checkingCount = final.Count() + final2.Count();
        Console.Write(checkingCount);
        Console.ReadLine();

看看这个,顺便说一下不太高效。但是做对了。


0
        string s1 = "aabcc";
        string s2 = "adcaa";
        int x = 0;

        var s1list = s1.ToList();
        var s2list = s2.ToList();
        for (int i=0; i<s1list.Count; i++)
        {
            var check = s1list[i];
            if (s2list.Contains(s1list[i]))
            {
                x++;
                var indexval = s2list.FindIndex(a => a == s1list[i]);
                s2list.RemoveAt(indexval);
            }
        }
        Console.WriteLine(x);

0

这个程序在处理更大的输入时会更快,因为它不使用嵌套循环,而是依赖于使用字典的哈希搜索。另一方面,它会使用更多的内存。

 public int CommonCharacterCount(string s1, string s2)
            { 
                var r=0;
                Dictionary<char,int> s2Dict = new Dictionary<char,int>();
                foreach (var ch in s2)
                {
                    if (s2Dict.ContainsKey(ch))
                        s2Dict[ch] = s2Dict[ch]+1;
                    else s2Dict.Add(ch,1);
                }

                foreach (var c in s1)
                {
                    if (s2Dict.ContainsKey(c) && s2Dict[c]>0)
                    {
                        r++;
                        s2Dict[c] = s2Dict[c] - 1;
                    }
                }
                return r;
            }

-3
请检查以下代码--> src 是第一个字符串,而 chk 是第二个字符串。

var count = 0;var i=0; src.ToList().ForEach((x)=> {
while(chk.Substring(i).IndexOf(x) >= 0) {
count++; i++; if( i > chk.Length) break; }
});


1
AAA怎么办? - L.B
3
194个答案后你还不知道如何格式化答案吗? - L.B
整数i被设置为0(零)。 - rt2800

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接