How to get top N elements of a list with LinQ?
我有一个按考试分数排序的列表,我想要这个列表的前n个元素。如果n(th)和n+1(th)学生的考试分数相同,则列表中必须同时包含这两个分数。
例如,我有一个这样的列表:
1 2 3 4 5 | john. 80 mike. 75 james. 70 ashley. 70 kate. 60 |
前三名应返回
英语不是我的主要语言,对不起,如果我说得不正确谢谢
以下是一个仅通过一次的实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | 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; } } } } |
示例用法:
1 2 3 4 5 6 7 8 9 10 11 12 13 | 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); } |
。
你可能想做的是
即
1 2 | var nth = users.Skip(n-1).FirstOrDefault() var top = users.TakeWhile(user => user.Score >= nth.Score) |
号
(这假设列表按降序排列,如问题中给出的示例所示。如果输入列表中有
也许是这样?
1 | list.TakeWhile((item, index) => index < N || list[index] == list[index + 1]); |
。
我在LinqPad中创建了一个示例案例。
1 2 3 4 5 6 7 8 | var a = new List<Tuple<string,int>>(); a.Add(new Tuple<string,int>("john",80)); a.Add(new Tuple<string,int>("mike",75)); a.Add(new Tuple<string,int>("james",70)); a.Add(new Tuple<string,int>("ashley",70 )); a.Add(new Tuple<string,int>("kate",60 )); a.Where(x=>x.Item2>=a.OrderBy(i=>i.Item2).Skip(2).Take(1).SingleOrDefault ().Item2).Dump(); |
但不知道它是否足够有效。
What if more than two students have the same marks? Will you take them all? OP: Yes
号
您可以按点分组,然后使用
1 2 3 4 | var topThreePoints = users.GroupBy(u => u.Points) .OrderByDescending(g => g.Key) .Take(3) .SelectMany(g => g); |