繁体   English   中英

从无序列表中按值获取有序的组列表的最佳方法

[英]Best way to get an ordered list of groups by value from an unordered list

我想知道是否有更有效的方法从最初的无序列表中获取有序的组列表,而不是使用GroupBy()后跟OrderBy() ,如下所示:

List<int> list = new List<int>();
IEnumerable<IEnumerable<int>> orderedGroups = list.GroupBy(x => x).OrderBy(x => x.Key);

有更多细节,我有一个大的List<T>我想要排序,但是有很多重复的值,所以我想将结果作为IEnumerable<IEnumerable<T>>返回,就像GroupBy()返回一个IEnumerable组。 如果我使用OrderBy() ,我只是得到IEnumerable<T> ,没有简单的方法来知道值是否已从一个项目更改为下一个项目。 我可以对列表进行分组,然后对组进行排序,但列表很大,因此最终变慢。 由于OrderBy()返回一个OrderedEnumerable ,然后可以使用ThenBy()在辅助字段上对其进行排序,因此它必须在内部区分具有相同或不同值的相邻项。

有没有什么方法可以利用OrderedEnumerable<T>必须在内部按值对其结果进行分组的事实(为了方便ThenBy() ),或者使用LINQ获取有序的组列表的最有效方法是什么?

  • 您可以使用ToLookup ,它返回IEnumerable<IGrouping<TKey, TElement> ,然后根据需要为每个键的值执行OrderBy 假设h是组下元素的数量,这将是O(n)创建查找和O(h)到每个组下的元素(键的值)

  • 您可以使用IDictionary<TKey, IOrderedEnumerable<T>>来提高性能以分摊O(n)。 但是如果你想通过多个属性进行排序,它将再次由O(h)组成。 有关IOrderedEnumerable的更多信息,请参阅此答案 您还可以使用SortedList<TKey, TValue>而不是IOrderedEnumerable

[更新]:

这是另一个你可以看一看的答案 但同样,它涉及在结果之上执行OrderBy。

此外,您可以提出自己的数据结构,因为我看不到满足此要求的BCL上可用的任何数据结构。

一种可能的实现:

你可以有一个二进制搜索树,它平均在O(longN)中搜索/删除/插入。 并且进行有序遍历将为您提供排序键。 例如,对于值,树上的每个节点都将具有有序集合。

节点大致如下所示:

public class MyNode
{
    prop string key;
    prop SortedCollection myCollection;
}

您可以遍历初始集合一次并创建此特殊数据结构,可以查询该结构以获得快速结果。

[更新2]:如果你有可能的密钥低于100k,那么我觉得实现你自己的数据结构是一种矫枉过正。 通常,订单将返回非常快,所花费的时间很少。 除非您拥有大量数据且多次订购,否则ToLookup应该可以正常工作。

老实说,你不会做得更好

items.GroupBy(i => i.KeyProperty).OrderBy(g => g.Key);

GroupByO(n)操作。 然后OrderByO(k log k) ,其中k是组的数量。

如果你先调用OrderBy ......首先,你的O(n log n)现在是你的项目数而不是你的组数,所以它已经慢于上面的速度了。

其次, IOrderedEnumerable 没有你认为它具有的内部魔力 它不是一个包含相同顺序项组的有序序列,然后可以通过ThenBy重新排序; 它是一个无序序列,带有ThenBy 添加的排序键列表,当你迭代它时,每个键最终会对它进行排序。

您可以通过滚动自己的“组和排序”循环来提高速度,也许手动添加到SortedDictionary<TKey, IList<TItem>> ,但我认为你不会得到一个比开箱即用的LINQ更好的大O.LINQ

我想在填充Dictionary<T, int>迭代通过列表for(;;) ,其中value是重复元素的计数将更快。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM