C# 如何使用LinQ获取列表的前N个元素?
我有一个按考试分数排序的列表,我希望列表中的前N个元素。C# 如何使用LinQ获取列表的前N个元素?,c#,linq,C#,Linq,我有一个按考试分数排序的列表,我希望列表中的前N个元素。 如果N(第N个)和N+1(第N个)学生的考试分数相同,则列表中必须同时包含这两个分数 例如,我有这样一个列表: john. 80 mike. 75 james. 70 ashley. 70 kate. 60 前三名应返回约翰、迈克、詹姆斯、阿什利 我尝试了Take(),但它只返回john、mike、james 英语不是我的主要语言,如果我说不正确,对不起 谢谢 如果两个以上的学生成绩相同怎么办?你都要吗?OP:
如果N(第N个)和N+1(第N个)学生的考试分数相同,则列表中必须同时包含这两个分数 例如,我有这样一个列表:
john. 80
mike. 75
james. 70
ashley. 70
kate. 60
前三名应返回约翰、迈克、詹姆斯、阿什利
我尝试了Take(),但它只返回john、mike、james
英语不是我的主要语言,如果我说不正确,对不起
谢谢
如果两个以上的学生成绩相同怎么办?你都要吗?OP:是
您可以按点分组,然后使用降序排序
+获取
+选择多个
:
var topThreePoints = users.GroupBy(u => u.Points)
.OrderByDescending(g => g.Key)
.Take(3)
.SelectMany(g => g);
你可能想做的是
得到第n个
当>=n时获取全部
i、 e
(假设列表按降序排列,如问题中给出的示例所示。如果输入列表中有我在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();
var a=新列表();
a、 添加(新元组(“john”,80));
a、 添加(新元组(“mike”,75));
a、 添加(新元组(“james”,70));
a、 添加(新元组(“ashley”,70));
a、 添加(新元组(“kate”,60));
a、 其中(x=>x.Item2>=a.OrderBy(i=>i.Item2).Skip(2).Take(1).SingleOrDefault().Item2.Dump();
但我不知道它是否足够有效。也许是这样
list.TakeWhile((item, index) => index < N || list[index] == list[index + 1]);
list.TakeWhile((项目,索引)=>index
这里是一个仅通过一次的实现:
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;
}
}
}
}
基本上,你的意思是<代码>有关系的,在SQL术语中,是吗?@沙哈里尔我尝试过这个代码>(n)< /代码>不考虑TimeRebug如果两个以上的学生有相同的分数怎么办?您愿意全部接受吗?@AhmetEmre90:请您通过编辑您的问题并提供更有意义的样本数据来澄清您的要求好吗?例如,如果有两个80分,两个70分,两个60分,你是想要得到六个项目还是想要得到两个80+70分?这需要前三组,但是-如果第一组有200个项目,你不会从任何其他组中得到任何项目groups@Marc,我不明白你的评论。如果第一组有200个项目,并且从前三组中选择了许多项目,那么结果肯定会包括这200个项目加上另外两组中的项目,对吗?@FrédéricHamidi如果目的是top WITH TIES
,则不会。@marcgravel:也许我对这个问题的理解不正确。但我想OP想把所有的领带都包括进去。为了它的价值,我和蒂姆一样阅读这个问题。还要注意的是,提问者从未承认Marc的评论,也可能根本没有在寻找一个关于领带的解决方案——这并不清楚。这看起来不错,但它可能会索引list[list.Length]
。我认为list[index]==list[index-1]
没有这个问题,因为index
在index
为0时保持不变。
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);
}