2

我以前没有做过很多 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 会产生一个结果。

提前致谢。

4

6 回答 6

3

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


这个怎么运作:

对于尺寸99第一范围,>= 99100. 因此,计算出的键值将是100。大小与 key 分组100

下一个尺寸98, 10,5也将获得密钥100并进入该组。

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

等等。

于 2012-11-19T10:46:43.160 回答
3

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

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

于 2012-11-19T10:48:59.613 回答
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,它的可读性更高。

于 2012-11-19T10:53:58.253 回答
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);
    }

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

于 2012-11-19T15:30:54.467 回答
0

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

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

于 2012-11-19T11:08:18.270 回答
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
--
于 2014-02-14T20:13:47.587 回答