根据组计数排序列表

我想对IGrouping的元素数量进行排序。

就是这样,理想情况下列表应该是相同的。 我会妥协一个新的列表,但那么元素应该是完全相同的原始对象,而不是副本(不管是浅的),绝对不是匿名对象。

具体来说:我们有一个具有许多属性的实体,以及这种类型的对象列表。 我们希望(1)通过某些属性(名称,地址,……)对对象进行分组,然后(2)计算每个组中元素的数量。 最后,我们希望(3)通过首先放置属于较大组的元素,根据这些计数对列表进行重新排序。

注意:我们的主要问题是我们似乎无法找到一种方法来保持对组元素中原始对象的引用。 事实上,我们可以在Linq查询中选择的是分组键(或键的属性),并且IGrouping不会显示任何其他内容。 我们无法弄清楚如何将组元素与列表元素相关联,而不是查看数据(即便如此,我们还需要主键,我们无法将其添加到分组键或它会破坏分组开始的目的)。

 var mySortedList = myList.GroupBy(x => x.Name).OrderByDescending(g => g.Count()) .SelectMany(x => x).ToList(); 

几乎没有.NET中的操作克隆对象。 既不深也不浅。 LINQ也不会克隆它处理的元素。 因此,一个简单的LINQ查询将起作用:

 var oldList = ...; var newList = (from x in oldList group x by something into g orderby g.Count() from x in g //flatten the groups select x).ToList(); 

此代码复制原始对象的引用 。 如果你不相信,你可能会误解你所看到的。

嗯,这很尴尬。

我的错误确实是基于一种误解:

 class Item { internal string Value { get; set; } internal string Qux { get; set; } internal string Quux { get; set; } } var query = from i in list group i by new { i.Value, i.Qux } into g // Note: no Quux, no primary key, just what's necessary orderby g.Count() descending, g.Key.Value select new { // [1] Value = g.Key.Value, Qux = g.Key.Qux, // Quux? } 

我的错误假设是[1]的选择是作用于个人记录,就像SQL一样。 好吧,希望我可以拯救那些有同样假设的人:事实并非如此。

现在看来很明显,但选择作用于各个组,因此这里将为每个组创建一个新对象,而不是为每个元素创建。

我的第二个错误是关注密钥,想知道如何在不使用它的情况下“传递”其他属性。 我还担心我们似乎需要对我们的物体进行浅层复制。 同样,这是基于以下事实:我们对IGrouping的行为方式一无所知:因为我们不知道我们在组上选择,所以我们甚至无法为select中的每个元素创建新对象。

解决方案绝对不令人印象深刻:

 var query = from i in list group i by new { i.Value, i.Qux } into g orderby g.Count() descending, g.Key.Value select g; foreach (var group in query) { foreach (var item in group) Console.WriteLine("{0} {1} {2} [Original object? {3}]", item.Value, item.Qux, item.Quux, list.Contains(item)); Console.WriteLine("-"); } 

输出:

 AAA Foo ... [Original object? True] AAA Foo ... [Original object? True] AAA Foo ... [Original object? True] - BBB Foo ... [Original object? True] BBB Foo ... [Original object? True] - AAA Bar ... [Original object? True] - CCC Foo ... [Original object? True] - DDD Foo ... [Original object? True] - DDD Bar ... [Original object? True] - EEE Foo ... [Original object? True] 

实际上, IGrouping元素是原始元素。 从那里我们可以创建一个没有任何问题的新列表。

更新:我在查询之外展平结果集主要是为了能够将组分隔符编写到控制台以进行演示,但是请参阅Tim和usr的答案,使用SelectMany (以及等效的Linq语法)在查询中展平。

毋庸置疑,这是另一个经典案例“我们太匆忙了,让我们来看看这里和那里的一些例子,那将是它”,正确的方法是花一点时间学习基础知识。 Linq不是SQL。

我为你可能浪费的时间道歉,试图消除困惑。 希望其他赶时间的人可能会从这些错误中受益。