2014-09-29 77 views
6

我有一個由考試點排序的列表,我想要列出這個列表的前N個元素。
如果N(第)和N + 1(th)個學生的考試分數相同,則該列表必須同時擁有這兩個分數。如何使用LinQ獲取列表的前N個元素?

比如我有一個這樣的名單:

john. 80 
mike. 75 
james. 70 
ashley. 70 
kate. 60 

前3名應該返回john, mike, james, ashley
我試圖採取(),但它僅返回john, mike, james

英語不是我的主要語言,對不起,如果我說不出來
謝謝

+0

那你試試? – Shaharyar 2014-09-29 12:24:20

+2

基本上,你的意思是'WITH TIES',用SQL術語來說,是嗎? – 2014-09-29 12:24:43

+0

@Shaharyar我試過這個http://stackoverflow.com/questions/319973/how-to-get-first-n-elements-of-a-list-in-c – AhmetEmre90 2014-09-29 12:25:18

回答

0

如果mo比兩名學生有相同的分數?你會把他們全部? OP:

您可以通過點組,然後用OrderByDescending + Take + SelectMany

var topThreePoints = users.GroupBy(u => u.Points) 
          .OrderByDescending(g => g.Key) 
          .Take(3) 
          .SelectMany(g => g); 
+3

這需要前3組,但 - 如果第一組有200個項目,你不會從任何其他組中取出任何 – 2014-09-29 12:25:56

+1

不會回答問題,仔細閱讀佇列 – 2014-09-29 12:26:02

+0

@Marc,我不明白你的意見。如果第一組有200個項目和來自前3個組的「SelectMany()'項目,那麼結果肯定會包括這200個項目加上其他兩組中的項目,對吧? – 2014-09-29 12:27:04

2

你可能想要做什麼是

  1. 獲得的第n個
  2. 當>> = n時得到全部

var nth = users.Skip(n-1).FirstOrDefault() 
var top = users.TakeWhile(user => user.Score >= nth.Score) 

(這假定列表被排序下降,如在問題給出的例子。如果在輸入列表中有<個元素,也會拋出錯誤)

0

我在LINQPad中創建了一個示例案例。

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(); 

雖然不知道它是否足夠有效。

0

也許是這樣嗎?

list.TakeWhile((item, index) => index < N || list[index] == list[index + 1]); 
+1

這看起來不錯,但它可能會對list [list.Length]進行索引。我認爲'list [index] == list [index - 1]'沒有這個問題,因爲當'index'是0時'index Lumen 2014-09-29 12:50:16

10

這裏有一通唯一實現:

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; 
      } 
     } 
    } 
} 

用法示例:

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); 
}