I would like to do something like this (below) but not sure if there is a formal/optimized syntax to do so?
.Orderby(i => i.Value1) .Take("Bottom 100 & Top 100") .Orderby(i => i.Value2);
basically, I want to sort by one variable, then take the top 100 and bottom 100, and then sort those results by another variable.
Any suggestions?
The Take operator is used to return a given number of rows from a database table and the Skip operator skips over a specifed number of rows in a database table. I create a data context class that has tables or a stored procedure.
Most of the times, LINQ will be a bit slower because it introduces overhead. Do not use LINQ if you care much about performance. Use LINQ because you want shorter better readable and maintainable code. So your experience is that LINQ is faster and makes code harder to read and to maintain?
var sorted = list.OrderBy(i => i.Value); var top100 = sorted.Take(100); var last100 = sorted.Reverse().Take(100); var result = top100.Concat(last100).OrderBy(i => i.Value2);
I don't know if you want Concat
or Union
at the end. Concat
will combine all entries of both lists even if there are similar entries which would be the case if your original list contains less than 200 entries. Union
would only add stuff from last100 that is not already in top100.
Some things that are not clear but that should be considered:
If list is an IQueryable
to a db, it probably is advisable to use ToArray()
or ToList()
, e.g.
var sorted = list.OrderBy(i => i.Value).ToArray();
at the beginning. This way only one query to the database is done while the rest is done in memory.
The Reverse
method is not optimized the way I hoped for, but it shouldn't be a problem, since ordering the list is the real deal here. For the record though, the skip method explained in other answers here is probably a little bit faster but needs to know the number of elements in list.
If list would be a LinkedList
or another class implementing IList
, the Reverse
method could be done in an optimized way.
You can use an extension method like this:
public static IEnumerable<T> TakeFirstAndLast<T>(this IEnumerable<T> source, int count) { var first = new List<T>(); var last = new LinkedList<T>(); foreach (var item in source) { if (first.Count < count) first.Add(item); if (last.Count >= count) last.RemoveFirst(); last.AddLast(item); } return first.Concat(last); }
(I'm using a LinkedList<T>
for last
because it can remove items in O(1)
)
You can use it like this:
.Orderby(i => i.Value1) .TakeFirstAndLast(100) .Orderby(i => i.Value2);
Note that it doesn't handle the case where there are less then 200 items: if it's the case, you will get duplicates. You can remove them using Distinct
if necessary.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With