【问题标题】:LINQ and GroupByLINQ 和 GroupBy
【发布时间】:2014-02-15 04:13:47
【问题描述】:

我以前没有做过很多 LINQ,所以我经常发现某些方面令人困惑。最近有人使用 GroupBy 运算符创建了一个如下所示的查询。他们是这样做的:

List<int> ranges = new List<int>() {100, 1000, 1000000};

List<int> sizes = new List<int>(new int[]{99,98,10,5,5454, 12432, 11, 12432, 992, 56, 222});

var xx = sizes.GroupBy (size => ranges.First(range => range >= size));

xx.Dump();

基本上我对键表达式的工作方式非常困惑,即 range.First(range => range >= size

谁能解释一下?是否可以进一步分解以使其更易于理解?我认为 First 会产生一个结果。

提前致谢。

【问题讨论】:

    标签: c# linq


    【解决方案1】:

    size =&gt; ranges.First(range =&gt; range &gt;= size) 这个 Func 构建键,大小将被分组。它采用当前大小并找到大于或等于当前大小的第一个范围。


    它是如何工作的:

    对于大小99 第一个范围&gt;= 99100。因此,计算出的键值为100。大小与键 100 进行分组。

    下一个尺寸98105 也将获得密钥100 并转到该组。

    对于大小5454,计算的键值将是1000000(它是大于5454 的第一个范围。因此,创建了新键,并且大小与键1000000 一起分组。

    等等

    【讨论】:

    • 非常感谢您的解释,非常有帮助。
    【解决方案2】:

    ranges.First(range =&gt; range &gt;= size) 返回一个int,第一个range&gt;= 当前的size 值。所以每个尺寸都属于一个范围。就是那个组。

    请注意,如果&gt;= 没有给定大小的范围,First 将引发异常。

    【讨论】:

      【解决方案3】:

      如果你用 for 循环编写代码,它看起来像这样:

      var myGroup = new Dictionary<int, List<int>>();
      
      foreach( size in sizes)
      {
          // ranges.First(range => range >= size) is like bellow
          range = find minimum value in ranges which is greater than equal to size;
      
          // this grouping will be done autamatically by calling GroupBy in your code:
          if (myGroup[range] has no value) // actually TryGetValue
            myGroup[range] = new List<int>();
      
          // this addition will be done by each iteration on your inputs.
          myGroup[range].Add(item);
      }
      

      您的 linq 命令的不同之处在于,它不适用于 for 循环,实际上它适用于哈希表,而且速度更快(平均而言),如果您学习 linq,它的可读性更高。

      【讨论】:

        【解决方案4】:

        不确定它是否增加了清晰度,但如果你真的想分解它,你可以执行以下操作(我猜你正在使用 LinqPad)

           List<int> ranges = new List<int>() {100, 1000, 1000000};
           List<int> sizes = new List<int>(new int[]{99,98,10,5,5454, 12432, 11, 12432, 992,    56, 222});
        
           void Main()
           {
                var xx = sizes.GroupBy (size => GetRangeValue(size));
        
                xx.Dump();
            }
        
           private int GetRangeValue(int size)
           {
                // find the first value in ranges which is bigger than or equal to our size
                return ranges.First(range => range >= size);
            }
        

        是的,你是对的,First 确实产生了一个结果。

        【讨论】:

          【解决方案5】:

          确实,先返回一个值,作为分组的key。

          这里发生的是 - 为每个大小的值调用 First,返回大于大小的第一个范围(100,100,100,100,1000000, 1000000 等) - “尺寸”按此值分组。例如,对于每个范围,都会返回一个分组 100: 99,98,10,5,11...

          【讨论】:

            【解决方案6】:

            GroupBy 实质上构建了一个查找表(字典),其中您的源中满足常见条件的每个项目分组到一个列表中,然后分配给查找表中的

            这里是一个示例程序,它将您对xx.Dump() 的调用替换为一个代码块,该代码块以特定于您的示例的方式漂亮地打印输出。请注意使用OrderBy 对键(范围值)以及与每个范围关联的项目组进行第一次排序。

            using System;
            using System.Collections.Generic;
            using System.Linq;
            
            class GroupByDemo
            {
                static public void Main(string[] args)
                {
                    List<int> ranges = new List<int>() {100, 1000, 1000000};
            
                    List<int> sizes = new List<int>(
                        new int[]{99,98,10,5,5454, 12432, 11, 12432, 992, 56, 222});
            
                    var sizesByRange =
                        sizes.GroupBy(size => ranges.First(range => range >= size));
            
                    // Pretty-print the 'GroupBy' results.
                    foreach (var range in sizesByRange.OrderBy(r => r.Key))
                    {
                        Console.WriteLine("Sizes up to range limit '{0}':", range.Key);
            
                        foreach (var size in range.ToList().OrderBy(s => s))
                        {
                            Console.WriteLine("  {0}", size);
                        }
                    }
                    Console.WriteLine("--");
                }
            }
            

            预期结果

            请注意,12432 在最后一组中出现了两次,因为该值在原始源列表中出现了两次。

            Sizes up to range limit '100':
              5
              10
              11
              56
              98
              99
            Sizes up to range limit '1000':
              222
              992
            Sizes up to range limit '1000000':
              5454
              12432
              12432
            --
            

            【讨论】:

              猜你喜欢
              • 2012-06-24
              • 1970-01-01
              • 2011-05-29
              • 1970-01-01
              • 2011-11-09
              • 2023-03-30
              • 1970-01-01
              • 2016-06-17
              • 1970-01-01
              相关资源
              最近更新 更多