【问题标题】:linq groupby and max countlinq groupby 和最大计数
【发布时间】:2021-10-11 00:25:02
【问题描述】:

我有一门课

public class Test
{
    public string name;
    public int status;
}

示例数据

new Test("Name1", 1);
new Test("Name2", 2);
new Test("Name3", 3);
new Test("Name4", 1);
new Test("Name5", 2);
new Test("Name6", 2);
new Test("Name7", 3);

我正在寻找一些 linq 来返回值 2 - 这是出现最多的状态。

目前我有以下不正确的。

  var status = listTest.GroupBy(x => x.status).Select(x => x.OrderByDescending(t => t.status).First()).FirstOrDefault().status;

但希望有更清洁的东西吗?

【问题讨论】:

  • 我确定这只是一个错字,但你为你的班级所说的不正确。首先,它使用 private 字段,其次,名称是小写,而您的查询使用大写。
  • 哎呀,错字已修复。

标签: c# linq


【解决方案1】:

我想这就是你想要的

您需要自己订购组,而不是每个组中的内容。

var status = listTest
    .GroupBy(x => x.Status)
    .OrderByDescending(g => g.Count())
    .FirstOrDefault()?.Key;

【讨论】:

    【解决方案2】:

    降序排列后,可以分组取顶

    var value = list.GroupBy(q => q.status)
                .OrderByDescending(gp => gp.Count())
                .First().Key;
    

    【讨论】:

      【解决方案3】:

      要求:给定一个Test类的对象序列,其中每个Test都有一个int属性Status,给我出现最多的Status值。

      为此,使 Groups Test 对象具有相同的属性 Status 值。计算每组中的元素数。对结果进行排序,使数字最大的组在前,并取第一个元素。

      IEnumerable<Test> testSequence = ...
      var statusThatOccursMost = testSequence
      
          // make Groups of Tests that have the same value for Status:
          .GroupBy(test => test.Status,
      
              // parameter resultSelector: for every occurring Status value and all
              // Tests with this common status value, make one new object,
              // containing the common Status value and the number of Tests that have
              // this common Status value
              (commonStatusValue, testsThatHaveThisCommonStatusValue) => new
              {
                  Status = commonStatusValue,
                  Count = testsThatHaveThisCommonStatusValue.Count(),
              })
      

      结果:一系列 [Status, Count] 组合。状态在 testSequence 中至少出现一次。 Count 是 Status 出现的次数。所以我们知道,Count >= 1。

      这个[Status, Count]组合序列按Count的降序排列,所以第一个元素是Count的最大值:

          .OrderByDescenting(statusCountCombination => statusCountCombination.Count)
      

      结果:[Status, Count] 组合的序列,其中 Count 值最大的组合在前。

      从组合中提取Status的值,取第一个:

          .Select(statusCountCombination => statusCountCombination.Status)
          .FirstOrDefault();
      

      优化

      虽然这个 LINQ 相当简单,但如果您只想要 Count 值最大的一个,那么对所有 Status 值进行计数并对所有 StatusCount 组合进行排序并不是很有效。

      考虑创建一个扩展方法。如果你不熟悉扩展方法,请阅读Extension Methods Demystified

      制作字典:关键是状态。值是此状态发生的次数。然后取 Count 最大的 Status

      public static int ToMostOccuringStatusValueOrDefault(
          this IEnumerable<Test> testSequence)
      {
          // return default if testSequence is empty
          if (!testSequence.Any()) return 0;
      
          Dictionary<int, int> statusCountCombinations = new Dictionary<int, int>();
          foreach (Test test in testSequence)
          {
              if (statusCountCombinations.TryGetValue(test.Status, out int count)
              {
                  // Status value already in dictionary: increase count:
                  statusCountCombinations[test.Status] = count + 1;
              }
              else
              {
                  // Status value not in dictionary yet. Add with count 1
                  statusCountCombinations.Add(test.Status, 1);
              }
          }
      

      GroupBy 的工作方式与上述类似,不同之处在于它将首先创建一个字典,其中每个值都是一个测试列表。然后 if 计算测试的数量,并丢弃列表。在扩展方法中,我们不必制作 List。

      继续扩展方法:找到Value最大的KeyValuePair。我们可以使用 Enumerable.Aggregate,或者枚举:

          using (var enumerator = statusCountCombinations.GetEnumerator())
          {
              // we know there is at least one element
              enumerator.MoveNext();
              // the first element is the largest until now:
              KeyValuePair<int, int> largest = enumerator.Current;
      
              // enumerate the rest:
              while (enumerator.MoveNext)
              {
                  if (enumerator.Current.Value > largest.Value)
                  {
                       // found a new largest one
                       largest = enumerator.Current;
                  }
              }
              return largest.Key;
          }
      }
      

      在这个方法中,我们只需要枚举一次 testSequence 和你的 Dictionary 一次。如果你使用 Linq GroupBy / OrderByDescending,GroupBy 的结果会被枚举多次

      用法:

      IEnumerable<Test> testSequence = ...
      var mostCommonStatus = testSequence.ToMostOccurringStatusValueOrDefault();
      

      【讨论】:

        猜你喜欢
        • 2011-11-09
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-09-29
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多