【问题标题】:C# Find most common strings in string arrayC#在字符串数组中查找最常见的字符串
【发布时间】:2016-09-20 15:44:55
【问题描述】:

我有这个问题。有一个字符串

string [5] names = { "John", "Sam", "Harry", "Sam", "John" }

我需要找到数组中最常见的元素。我尝试使用:

string MostCommon = names.GroupBy(v => v)
    .OrderByDescending(g => g.Count())
    .First()
    .Key;

不幸的是,它只找到一个元素,例如MostCommon = John,在这种情况下,我不仅需要John,还需要Sam。我怎么能那样做?也许在这种情况下不需要 LINQ?

【问题讨论】:

  • .First() 是你的问题。去掉.First(),你会得到不止一个结果,但你不会知道那个单一的LINQ语句的具体计数是什么。
  • 不,那个重复是 OP 想要避免的,只选择第一个最大值。它不处理 OP 的情况,其中一个以上的成员可能具有最大计数。

标签: c# arrays string linq


【解决方案1】:

First 显然只会选择序列的第一个元素。但是,您需要具有相同数量的所有组。所以选择每个组的名称和编号,然后排序。最后选择所有与第一组具有相同计数的组。

var groups = names.GroupBy(x => x)
    .Select(x => new { x.Key, Count = x.Count() })
    .OrderByDescending(x => x.Count);
int max = groups.First().Count;
var mostCommons = groups.Where(x => x.Count == max);

编辑:您还可以在最后一个语句中使用TakeWhile 而不是Where,这将避免对groups-list 中的最后一个元素进行不必要的比较,并在发现第一组的元素少于第一个:

var mostCommons = groups.TakeWhile(x => x.Count == groups.First().Count);

【讨论】:

  • 这是一种非常低效的方式,它会多次执行groups 查询(涉及分组和排序)。至少将groups.First().Count 放入最后一个查询之外的变量中,以使groups 查询“仅”执行两次。它仍然会比 Amit Hasan 方法更糟糕(并且不计算可能的非 LINQ 解决方案),但至少可以认为还不错。
  • 关于TakeWhile 相对于Where 的优势,这是一个很好的观点。为了未来读者的利益,我认为您应该考虑使用TakeWhile 添加一个sn-p,甚至可能完全删除Where 代码,因为TakeWhile 是更好的选择。
  • @BACON 完成了。
  • @IvanStoev 按照建议完成,但是我怀疑是否有一种方法可以避免执行组语句两次,即使在您引用的答案中,namegroup 也被迭代了两次。我们可以使用ToList 强制立即评估,但到目前为止,两种解决方案的性能应该相似。我使用非 LINQ 方法对此进行了测试,该方法还需要对原始序列进行两次迭代。
  • @HimBromBeere 正确。关键是不要执行 N 次 :) Max + Where 的方法更好,因为即使通过 2 次也是 O(N)。正如你所知,OrderByDescending + First 是 O(N * lg(N))。 GroupBy 在这两种情况下的操作都是 O(N),所以我不计算它。
【解决方案2】:

这可以按如下方式完成 -

 var nameGroup = names.GroupBy(x => x);
 var maxCount = nameGroup.Max(g => g.Count());
 var mostCommons = nameGroup.Where(x => x.Count() == maxCount).Select(x => x.Key).ToArray();

【讨论】:

    【解决方案3】:

    根据您找到的最常用名称的计数,将您的第一个 LINQ 与另一个类似的 linq 组合。

    string MostCommon = names.GroupBy(v => v)
        .OrderByDescending(g => g.Count())
        .First();
    
    int count = names.Where(x => x == MostCommon).Count();
    
    var mostCommonList = names.GroupBy(v => v)
        .Where(g => g.Count() == count);
    

    【讨论】:

    • 由于最后一行不存在.Key 属性(加上分配mostCommonList 中的附加=),因此无法编译。不能假设只有一个“最常用的名字”,所以结果需要是IEnumerable<string> 而不是string。因此,.Key 需要被删除(或者用.Select(v => v) 替换,用处不大)。
    • @BACON 太多糟糕的副本/意大利面,谢谢你叫我出来。我修复了 = 并删除了两个 .Key 语句。我认为没有.Select() 的答案应该没问题,因为.Where 将返回一个可枚举的。
    【解决方案4】:
    //With Dictionary
    //This is more useful if you are looking to interview big companies otherwise use the 
     Linq option which is short and handy
    
    public static int MaxOccurrenceOfWord(string[] words)
        {
            var counts = new Dictionary<string, int>();
            int occurrences = 0;
            foreach (var word in words)
            {
                int count;
                counts.TryGetValue(word, out count);
                count++;
                 //Automatically replaces the entry if it exists;
                //no need to use 'Contains'
                counts[word] = count;
            }
    
            string mostCommonWord = null;
            foreach (var pair in counts)
            {
                if (pair.Value > occurrences)
                {
                    occurrences = pair.Value;
                    mostCommonWord = pair.Key;
                }
            }
            Console.WriteLine("The most common number is {0} and it appears {1} times",
                mostCommonWord, occurrences);
    
            return occurrences;
    
        }
    

    【讨论】:

      猜你喜欢
      • 2015-11-29
      • 2019-07-16
      • 2011-02-03
      • 2020-02-23
      • 2012-12-08
      • 1970-01-01
      • 2014-05-24
      • 2017-03-30
      • 1970-01-01
      相关资源
      最近更新 更多