c# - OrderBy and Top in LINQ with good performance -


what way top 10 records large collection , use custom orderby? if use linq objects orderby method slow , takes lot of memory because creates entire new collection new order. new method signature below not re-order entire collection , fast:

public static ienumerable<tsource> orderbytop<tsource, tkey>(     ienumerable<tsource> source,     func<tsource, tkey> keyselector,     icomparer<tkey> comparer,     int topcount) 

i tried write got complicated , thought there might easier way using aggregate or something. appreciated.

answer

thanks help. ended code below:

public static list<tsource> orderbytop<tsource, tkey>(     ienumerable<tsource> source,     func<tsource, tkey> keyselector,     icomparer<tkey> comparer,     int topcount) {     var itemcomparer = keyselector.toicomparer(comparer);     return source.aggregate(         new list<tsource>(topcount),         (list<tsource> list, tsource item) =>             list.sortedinsert(item, itemcomparer, topcount)); } 

the list extension method sortedinsert follows:

public static list<t> sortedinsert<t>(     list<t> list,     t item,     icomparer<t> comparer,     int maxlength) {     if (list.count == maxlength)         if (comparer.compare(item, list[maxlength - 1]) >= 0)             return list;         else             list.removeat(maxlength - 1);     int insertindex = list.binarysearch(item, comparer);     if (insertindex < 0)         insertindex = ~insertindex;     list.insert(insertindex, item);     return list; } 

for interested had keyselector extension method convert icomparer.

public static icomparer<tsource> toicomparer<tsource, tkey>(     func<tsource, tkey> keyselector,     icomparer<tkey> comparer) {     return new keyselectortoicomparerconverter<tsource, tkey>(         keyselector,         comparer); } private class keyselectortoicomparerconverter<tsource, tkey>     : icomparer<tsource> {     private readonly icomparer<tkey> comparer;     private readonly func<tsource, tkey> keyselector;     public keyselectortoicomparerconverter(         func<tsource, tkey> keyselector,         icomparer<tkey> comparer)     {         this.comparer = comparer;         this.keyselector = keyselector;     }     public int compare(tsource x, tsource y)     {         return comparer.compare(keyselector(x), keyselector(y));     } } 

aggregate place start with:

sortedlist<tkey, tsource> resultlist = new sortedlist<tkey, tsource>(); mybiglist.aggregate(resultlist, (aktlist,entry) => {    aktlist.add(entry.key, entry);    if (aktlist.count > 10) aktlist.removeat(10);    return aktlist; }); 

if want different comparer, can specify 1 in constructor of sortedlist.

edit mentioned nikie, sortedlistcannot contain double values. can use standard list binarysearch achieve same effect:

list<tsource> resultlist = new list<tsource>(); mybiglist.aggregate(resultlist, (aktlist, entry) => {    int index = aktlist.binarysearch(entry);    if (index < 0) index = ~index;    if (index < 10) aktlist.insert(index, entry);    if (aktlist.count > 10) aktlist.removeat(10);    return aktlist; }); 

again custom comparer (together custom key selection) can used parameter binarysearch.


Comments

Popular posts from this blog

unicode - Are email addresses allowed to contain non-alphanumeric characters? -

C#: Application without a window or taskbar item (background app) that can still use Console.WriteLine() -

c++ - Convert big endian to little endian when reading from a binary file -