【问题标题】:Find character with most occurrences in string?查找字符串中出现次数最多的字符?
【发布时间】:2021-06-12 10:53:15
【问题描述】:

例如,我有一个字符串:

"abbbbccd"

b 出现次数最多。使用 C++ 时,最简单的处理方法是将每个字符插入到 map<> 中。我必须在 C# 中做同样的事情吗?有没有使用 LINQ 的优雅方法?

【问题讨论】:

    标签: c# linq


    【解决方案1】:
    input.GroupBy(x => x).OrderByDescending(x => x.Count()).First().Key
    

    注意事项:

    【讨论】:

    • 请注意,.NET Core 现在有一个 microoptimization 代表 OrderBy(...).First(),所以现在是 O(n) 而不是 O(n log n)
    【解决方案2】:

    这是因为有人要求 2.0 版本,所以没有 LINQ。

    Dictionary<char, int> dict = new Dictionary<char, int>();
    
    int max = 0;
    
    foreach (char c in "abbbbccccd")
    {
        int i;
        dict.TryGetValue(c, out i);
        i++;
        if (i > max)
        {
            max = i;
        }
        dict[c] = i;
    }
    
    foreach (KeyValuePair<char, int> chars in dict)
    {
        if (chars.Value == max)
        {
            Console.WriteLine("{0}: {1}", chars.Key, chars.Value);
        }
    }
    

    对于 LINQ 版本,这是相反的。它将提取成对的“最佳”(aaaabbbb == a,b)。如果 str == String.Empty 将不起作用。

    var str = "abbbbccccd";
    
    var res = str.GroupBy(p => p).Select(p => new { Count = p.Count(), Char = p.Key }).GroupBy(p => p.Count, p => p.Char).OrderByDescending(p => p.Key).First();
    
    foreach (var r in res) {
        Console.WriteLine("{0}: {1}", res.Key, r);
    }
    

    【讨论】:

      【解决方案3】:
      string testString = "abbbbccd";
      var charGroups = (from c in testString
                          group c by c into g
                          select new
                          {
                              c = g.Key,
                              count = g.Count(),
                          }).OrderByDescending(c => c.count);
      foreach (var group in charGroups)
      {
          Console.WriteLine(group.c + ": " + group.count);
      }
      

      【讨论】:

        【解决方案4】:

        灵感来自斯蒂芬的回答,几乎相同:

        public static IEnumerable<T> Mode<T>(this IEnumerable<T> input)
        {
            var dict = input.ToLookup(x => x);
            if (dict.Count == 0)
                return Enumerable.Empty<T>();
            var maxCount = dict.Max(x => x.Count());
            return dict.Where(x => x.Count() == maxCount).Select(x => x.Key);
        }
        
        var modes = "".Mode().ToArray(); //returns { }
        var modes = "abc".Mode().ToArray(); //returns { a, b, c }
        var modes = "aabc".Mode().ToArray(); //returns { a }
        var modes = "aabbc".Mode().ToArray(); //returns { a, b }
        

        更新:对这个答案与Jodrell's 答案进行了快速基准测试(发布版本,调试器分离,哦,是的)

        来源 = "";

        迭代次数 = 1000000

        结果:

        this - 280 ms
        Jodrell's - 900 ms
        

        source = "aabc";

        迭代次数 = 1000000

        结果:

        this - 1800 ms
        Jodrell's - 3200 ms
        

        source = 相当大的字符串 - 3500+ 个字符

        迭代次数 = 10000

        结果:

        this - 3200 ms
        Jodrell's - 3000 ms
        

        【讨论】:

        • 我几乎有兴趣进行性能比较。里面可能没有多少。
        • @Jodrell 发布它,如果你这样做。我也会从我身边尝试。
        【解决方案5】:

        编辑 3

        这是我的最后一个答案,我认为(只是)降低了 Nawfal 在较长序列上的表现。

        但是,考虑到 Nawfal's answer 的复杂性降低,以及它更通用的性能,尤其是与问题相关的性能,我会选择它。

        public static IEnumerable<T> Mode<T>(
            this IEnumerable<T> source,
            IEqualityComparer<T> comparer = null)
        {
            var counts = source.GroupBy(t => t, comparer)
                .Select(g => new { g.Key, Count = g.Count() })
                .ToList();
        
            if (counts.Count == 0)
            {
                return Enumerable.Empty<T>();
            }
        
            var maxes = new List<int>(5);
            int maxCount = 1;
        
            for (var i = 0; i < counts.Count; i++)
            {
                if (counts[i].Count < maxCount)
                {
                    continue;
                }
        
                if (counts[i].Count > maxCount)
                {
                    maxes.Clear();
                    maxCount = counts[i].Count;
                }
        
                maxes.Add(i);
            }
        
            return maxes.Select(i => counts[i].Key);
        }
        

        编辑 2


        编辑



        如果您想要一个高效的通用解决方案,即考虑到多个项目可能具有相同频率的事实,请从这个扩展开始,

        IOrderedEnumerable<KeyValuePair<int, IEnumerable<T>>>Frequency<T>(
            this IEnumerable<T> source,
            IComparer<T> comparer = null)
        {
            return source.GroupBy(t => t, comparer)
                .GroupBy(
                    g => g.Count(),
                    (k, s) => new KeyValuePair<int, IEnumerable<T>>(
                        k,
                        s.Select(g => g.First())))
                .OrderByDescending(f => f.Key);
        }
        

        此扩展适用于以下所有场景

        var mostFrequent = string.Empty.Frequency().FirstOrDefault();
        
        var mostFrequent = "abbbbccd".Frequency().First();
        

        或者,

        var mostFrequent = "aaacbbbcdddceee".Frequency().First();
        

        请注意,mostFrequentKeyValuePair&lt;int, IEnumerable&lt;char&gt;&gt;


        如果你有这样的想法,你可以将它简化为另一个扩展,

        public static IEnumerable<T> Mode<T>(
            this IEnumerable<T> source,
            IEqualityComparer<T> comparer = null)
        {
            var mode = source.GroupBy(
                    t => t,
                    (t, s) => new { Value = t, Count = s.Count() }, comparer)
                .GroupBy(f => f.Count)
                .OrderbyDescending(g => g.Key).FirstOrDefault();
        
            return mode == null ? Enumerable.Empty<T>() : mode.Select(g => g.Value);
        }
        

        显然可以这样使用,

        var mostFrequent = string.Empty.Mode();
        
        var mostFrequent = "abbbbccd".Mode();
        
        var mostFrequent = "aaacbbbcdddceee".Mode();
        

        这里,mostFrequentIEnumerable&lt;char&gt;

        【讨论】:

        • 不错的解决方案。我认为它与 xanatos 的第二个答案相同,但需要额外检查空集合检查,这很好。顺便说一句,最常见的事情叫做众数,而不是中位数。
        • @nawfal,我想知道为什么我犯了这么愚蠢的错误。无论如何,它也与阿尔宾的答案基本相同,除了空支票和创世记。我不明白为什么流行但劣质的答案不断获得选票。
        • Jodrell,简单,一见钟情是最短最甜美的。或者可能就是他们想要的功能;)
        • +1 用于基准测试 :) Here is another alternative from David B
        • @nawfal,已修复。我必须转录我的代码才能把它放在这里,而且很容易出现我的人为错误。
        【解决方案6】:

        找到最简单且不使用内置函数的方法

        示例代码和链接

        public char MostOccurringCharInString(string charString)
        {
        int mostOccurrence = -1;
        char mostOccurringChar = ' ';
        foreach (char currentChar  in charString)
        {
            int foundCharOccreence = 0;
            foreach (char charToBeMatch in charString)
            {
                if (currentChar == charToBeMatch)
                    foundCharOccreence++;
            }
            if (mostOccurrence < foundCharOccreence)
            {
                mostOccurrence = foundCharOccreence;
                mostOccurringChar = currentChar;
            }
         }
          return mostOccurringChar;
        }
        

        了解更多关于如何获得最大出现次数以及流程是什么。

        How to get max occurred character and max occurrence in string

        【讨论】:

          【解决方案7】:
          #simplified expression using LINQ#
          string text = "abccdeeef";
          int length = text.ToCharArray().GroupBy(x => x).OrderByDescending(x => 
          x.Count()).First().Count();
          

          【讨论】:

          • 欢迎来到 Stack Overflow,感谢您发布答案!通常,只是没有任何解释的代码的答案会被删除/否决。我建议在您的代码中添加一些解释,以便将来的查看者能够理解它。
          【解决方案8】:

          有很多不同的方法可以解决这个问题。

          1. 林克
          2. 字典
          3. 使用系统。

          您可以根据自己的喜好进行选择。列出其中之一。

            private static void CalculateMaxCharCountUsingArray(string actualString)
                  {
                      char[] charArray = actualString.ToCharArray();
          
                      int[] arr = new int[256];
                      int maxCount = 0;
                      char maxChar = ' ';
                      foreach (var r in charArray)
                      {
                          arr[r] = arr[r] + 1;
                          if (maxCount < arr[r])
                          {
                              maxCount = arr[r];
                              maxChar = r;
                          }
                      }
                      Console.WriteLine("This character " + maxChar + " that appeared maximum times : " + maxCount);
          
                      IEnumerable<char> distinctCharArray = charArray.Distinct();
          
                      foreach(var r in distinctCharArray)
                      {
                          Console.WriteLine("This character " + r + " that appeared  times " + arr[r]  + " in a string");
          
                      }
                  }
          

          我都是从下面link学到的,供大家参考。

          【讨论】:

          • 只有 256 个字符?试试统一码。另外,问题是如何在 LINQ 中做到这一点。
          【解决方案9】:

          代码:

          class CharCount
          {
              public void CountCharacter()
              {
                  int n;
                  Console.WriteLine("enter the no. of elements: ");
                  n = Convert.ToInt32(Console.ReadLine());
          
                  char[] chararr = new char[n];
                  Console.WriteLine("enter the elements in array: ");
                  for (int i = 0; i < n; i++)
                  {
                      chararr[i] = Convert.ToChar(Console.ReadLine());
                  }
                  Dictionary<char, int> count = chararr.GroupBy(x => x).ToDictionary(g => g.Key, g => g.Count());
          
                  foreach(KeyValuePair<char, int> key in count)
                  {
                      Console.WriteLine("Occurrence of {0}: {1}",key.Key,key.Value);
                  }
          
                  Console.ReadLine();
              }
          }
          

          【讨论】:

          • 此代码显示每个字母的频率,而不是问题中要求的最大频率。
          【解决方案10】:
                  //find most occuring character and count from below string
          
                  string totest = "abcda12Zernn111y";
          
                  string maxOccuringCharacter = "";
                  int maxOccurence = 0;string currentLoopCharacter = ""; string updatedStringToTest = "";int cnt = 0;
          
                  for (int i = 0; i < totest.Length; i++)
                  {
                      currentLoopCharacter = totest[i].ToString();
                      updatedStringToTest = totest.Replace(currentLoopCharacter, "");
          
                      cnt = totest.Length - updatedStringToTest.Length;
          
                      if (cnt > maxOccurence)
                      {
                          maxOccuringCharacter = currentLoopCharacter;
                          maxOccurence = cnt;
                      }
          
                      totest = updatedStringToTest;
                  }
          
                  Console.WriteLine("The most occuring character is {0} and occurence was {1}", maxOccuringCharacter, maxOccurence.ToString());
                  Console.ReadLine();
          

          【讨论】:

            【解决方案11】:

            这是 Femaref 的解决方案,修改后返回多个字母,如果它们的 Count 匹配。它不再是单行代码,但仍然相当简洁,并且应该具有相当的性能。

                public static IEnumerable<char> GetMostFrequentCharacters(this string str)
                {
                    if (string.IsNullOrEmpty(str))
                        return Enumerable.Empty<char>();
            
                    var groups = str.GroupBy(x => x).Select(x => new { Letter = x.Key, Count = x.Count() }).ToList();
                    var max = groups.Max(g2 => g2.Count);
                    return groups.Where(g => g.Count == max).Select(g => g.Letter);
                }
            

            【讨论】:

              【解决方案12】:

              使用 LINQ 和 Dictionary 数据结构作为查找列表的不同方法:

                      var str = "abbbbccd";
                      var chrArr = str.ToCharArray();
                      Dictionary<char, int> dic = new Dictionary<char, int>();
                      foreach (char a in chrArr)
                      {
                          if (dic.ContainsKey(a))
                              dic[a]++;
                          else
                              dic.Add(a, 1);
                      }
                      int count = dic.Values.Max();
                      char val = dic.Where(d => d.Value == count).FirstOrDefault().Key;
              

              【讨论】:

                猜你喜欢
                • 2021-03-19
                • 2014-03-28
                • 2020-02-21
                • 2015-01-10
                • 1970-01-01
                • 2017-05-08
                • 1970-01-01
                相关资源
                最近更新 更多