LINQ和GroupBy

时间:2012-11-19 10:44:31

标签: c# linq

之前我没有做太多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();

基本上我对关键表达式如何工作非常困惑,即ranges.First(range =&gt; range&gt; = size

任何人都能解开一些光明吗?是否可以进一步分解以使其更容易理解?我认为First会产生一个结果。

提前致谢。

6 个答案:

答案 0 :(得分:3)

size => ranges.First(range => range >= size)此Func构建密钥,将对其进行分组。它需要当前大小并找到第一个范围,即大于或等于当前大小。


工作原理:

对于99 >= 99 100的第一个范围100。因此,计算的键值将为100。大小按键98进入分组。

下一个尺寸105100也会获得密钥5454并转到该组。

对于大小1000000,计算出的键值将为5454(它是第一个大于1000000的范围。因此,创建了新密钥,并且大小变为带密钥的组{ {1}}。

答案 1 :(得分:3)

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

请注意,First如果没有>=给定大小的范围,则会引发异常。

答案 2 :(得分:1)

如果用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,它更具可读性。

答案 3 :(得分:1)

不确定它是否会增加清晰度,但如果你真的想要打破它,你可以做以下事情(我猜你正在使用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);
    }

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

答案 4 :(得分:0)

实际上,首先返回一个值,这将成为分组的关键。

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

答案 5 :(得分:0)

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