A single pass implementation is implemented here:
public static IEnumerable<TSource> TopWithTies<TSource, TValue>( this IEnumerable<TSource> source, int count, Func<TSource, TValue> selector) { if (source == null) throw new ArgumentNullException("source"); if (selector == null) throw new ArgumentNullException("selector"); if (count < 0) throw new ArgumentOutOfRangeException("count"); if (count == 0) yield break; using(var iter = source.OrderByDescending(selector).GetEnumerator()) { if(iter.MoveNext()) { yield return iter.Current; while (--count >= 0) { if(!iter.MoveNext()) yield break; yield return iter.Current; } var lastVal = selector(iter.Current); var eq = EqualityComparer<TValue>.Default; while(iter.MoveNext() && eq.Equals(lastVal, selector(iter.Current))) { yield return iter.Current; } } } }
Usage example:
var data = new[] { new { name = "john", value = 80 }, new { name = "mike", value = 75 }, new { name = "james", value = 70 }, new { name = "ashley", value = 70 }, new { name = "kate", value = 60 } }; var top = data.TopWithTies(3, x => x.value).ToList(); foreach(var row in top) { Console.WriteLine("{0}: {1}", row.name, row.value); }
source share