【问题标题】:Find number of characters mutual between two strings in C#在C#中查找两个字符串之间相互的字符数
【发布时间】:2014-02-13 08:55:13
【问题描述】:

我正在寻找一种方法,该方法将采用两个字符串并返回两个字符串共有的字符数,例如:

“G010”和“G1820A”应该返回 3,因为 G、0 和 1 字符都存在于两者中。

如果一个char在两者中都存在两次,则应分别计算如下:

“G12AA”和“GAA2”应返回 4,因为 G、A、A 和 2 字符都存在。

对此有什么帮助吗?到目前为止,Google 搜索并没有太大帮助。

【问题讨论】:

  • 可能是经典的,但是到目前为止,您尝试过任何东西吗?
  • 我有一个方法可以比较两个字符串的相似性,但相同索引中的字符,这是完全不同的。
  • "G12AA" & "GA2" 应该返回 4? “GA2”和“G12AA”应该返回 4?

标签: c# string linq string-comparison stringcomparer


【解决方案1】:

好吧,这个怎么样,它的优点是最大化惰性求值和最小化字符串操作。

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&lt;T&gt;,然后将 sum 添加到调用中,像这样,

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();

【讨论】:

    【解决方案2】:

    试试这个

        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);
        }
    

    【讨论】:

    • 在你的条件下颠倒语句的顺序以提高效率:当标志意味着它不会被使用时,做所有额外的工作将字符串更改为数组是没有意义的!
    • 我的意思是改变条件的顺序: if (s1[i1] == s2[i2] && !matchedFlag[i2]): 先检查布尔值更有效:改为 if (! matchedFlag[i2] && s1[i1] == s2[i2]) - 见“短路” :) (现在您在第一个条件下正确使用字符串索引器,这将产生多大的影响值得怀疑 -必须是一个非常大的数据集 - 但我总是强调将最简单的条件放在使用 && 的 if 语句的开头:可以产生很大的不同,尤其是在多个循环中)
    • 哎呀我的错,感觉今天早上我还没有完全起床。
    • 呵呵,不用担心 - 现在失去 tochararray 调用 - 它们也是多余的;)
    • 如果您在谈论“G12A”和“GAA2”,则返回 3.G、A 和 2。
    【解决方案3】:

    您可以使用 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 方法的灵感来自这个问题:How do I do an integer list intersection while keeping duplicates?

    【讨论】:

    【解决方案4】:
            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"; 有什么用?
    • 当 s2 = "GAA2" s1 中出现所有 4 个字符时,4 怎么错?
    • @Amit 但他们都有一个共同的“A”而不是两个。参见 Tommy 的第一个示例
    • 感谢@L.B 告知重复字符的场景
    【解决方案5】:

    用 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;
                                });
        }
    

    【讨论】:

      【解决方案6】:

      这个会在更大的输入下运行得更快,因为它不进行嵌套循环,而是依赖于使用字典的散列搜索。另一方面,它使用更多的内存。

       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;
                  }
      

      【讨论】:

        【解决方案7】:
        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();
        

        检查一下,顺便说一句效率不高。但是没看错。

        【讨论】:

          【解决方案8】:
                  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);
          

          【讨论】:

            【解决方案9】:

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

            var count = 0;var i=0; src.ToList().ForEach((x)=> {
            而(chk.Substring(i).IndexOf(x) >= 0) {
            计数++; 我++; if(i > chk.Length) 中断; }
            });

            【讨论】:

            • AAA 怎么样?
            • 194个答案后仍然不知道如何格式化答案?
            • 整数 i 设置为 0(零)
            猜你喜欢
            • 2020-06-03
            • 1970-01-01
            • 2014-12-07
            • 1970-01-01
            • 1970-01-01
            • 2021-07-30
            • 1970-01-01
            • 1970-01-01
            • 2011-03-23
            相关资源
            最近更新 更多