内存优化OrderBy和Take?

我有9 GB的数据,我只想要10行。 当我做:

data.OrderBy(datum => datum.Column1) .Take(10) .ToArray(); 

我得到一个OutOfMemoryException 。 我想使用OrderByAndTake方法,针对较低的内存消耗进行了优化。 这很容易写,但我猜有人已经这样做了。 我在哪里可以找到它。

编辑 :这是Linq-to-objects。 数据来自文件。 如果Column1值小于10个最大值的当前列表,则可以丢弃每一行。

我假设你在Linq to Objects中这样做。 你可以做点什么……

 var best = data .Aggregate(new List(), (soFar, current) => soFar .Concat(new [] { current }) .OrderBy(datum => datum.Column1) .Take(10) .ToList()); 

通过这种方式,并非所有项目都需要保存在新的排序集合中,而不是您感兴趣的最佳项目。

这是代码最少的方式。 由于您知道soFar列表已排序,因此可以优化测试何处/是否插入current值。 我不想为你做所有的工作。 😉

PS:用你喜欢的任何类型替换T

编辑:考虑一下,最有效的方法实际上是一个简单的旧的foreach ,将每个项目与最佳10的运行列表进行比较。

它表示:OrderBy是一个Sort,它需要存储所有元素(延迟执行被取消)。

data是IQueryable时,它应该有效地工作,然后由数据库决定。


  // just 4 fun public static IEnumerable TakeDistinctMin(this IEnumerable @this, int n, Func selector) where TKey: IComparable { var tops = new SortedList(n+1); foreach (var item in @this) { TKey k = selector(item); if (tops.ContainsKey(k)) continue; if (tops.Count < n) { tops.Add(k, item); } else if (k.CompareTo(tops.Keys[tops.Count - 1]) < 0) { tops.Add(k, item); tops.RemoveAt(n); } } return tops.Values; } 

要订购一组无序对象,您必须查看所有这些对象,不是吗?

我不知道你怎么能够避免解析所有9 GB的数据以获得前10个以某种方式排序的数据,除非9 GB的数据已经以这种方式排序或者有索引或其他辅助数据可以利用的结构。

你能否提供更多关于你问题的背景知识。 您是使用LINQ to SQL或Entity Framework还是其他O / RM查询数据库?

您可以将这样的东西与投影比较器一起使用:

 public static IEnumerable OrderAndTake(this IEnumerable seq,int count,IComparer comp) { var resultSet=new SortedSet(comp); foreach(T elem in seq) { resultSet.Add(elem); if(resultSet.Count>count) resultSet.Remove(resultSet.Max); } return resultSet.Select(x=>x); } 

运行时应该是O(log(count)*seq.Count())和空格O(min(log(count),seq.Count()))

一个问题是,如果你有两个元素comp.Compare(a,b)==0 ,它将会中断comp.Compare(a,b)==0因为该集合不允许重复条目。