我试图从包含以下内容的CSV数据文件中获取GPA最高的学生的姓名: ID ,姓名,主题,得分。我能够解决我的要求,但我想知道是否有更好的方法。我很确定有,但我是LINQ的新手,想看看你的建议是什么。
我有可用的数据文件here。
我有以下代码:
using System;
using System.IO;
using System.Linq;
public class Program
{
public static void Main()
{
const string fileName = @"c:\temp\scores.csv";
String[] lines = File.ReadAllLines(fileName);
var studentData = from l in lines
// Skip header row.
.Skip(1)
// Split by comma.
let x = l.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries)
// Parsed out into fields.
select new
{
ID = Convert.ToInt32(x.ElementAt(0))
, Name = x.ElementAt(1)
, Subject = x.ElementAt(2)
, Grade = Convert.ToInt32(x.ElementAt(3))
};
var studentAvgRank = from b in studentData
// Grouping by name.
.GroupBy(g => g.Name)
// Interested in the averages for each students total scores.
.Select(g => new
{
Name = g.Key
, Avg = g.Average(c => c.Grade)
})
// In descending order.
orderby b.Avg descending
// We're only interested in the name, but just in case we can get the average too.
select b;
// Output only the name of the highest average student, so select name of first entry in sorted list.
Console.WriteLine(studentAvgRank.First().Name);
}
}
答案 0 :(得分:1)
使用CsvHelper而不是linq,它比linq快得多。您可以将linq与该库一起使用来执行操作。 对于I / O操作,应该避免使用linq并使用读者。
希望它有所帮助!!
答案 1 :(得分:1)
代码中最耗时的部分是这一部分:
String[] lines = File.ReadAllLines(fileName);
相反,您可以通过并行读取文件行来改进它, 现在每台普通的PC都支持并行IO。
要同时阅读该文件,您可以使用Parallel.ForEach
并维护您可能使用的学生列表ConcurrentQueue
。之后,您对该队列的当前linq查询应该没问题(除非您必须以某种方式阻止在队列中添加第一行)。
最后一点是,可能有多个学生具有最大平均学位,因此第一个或默认不是一个好的选择。相反,您可以找到最大GPA,然后输出拥有最大GPA的每个人。
答案 2 :(得分:1)
我正在考虑你的意思"优化Linq Querying"更多的是关于比实际运行时优化更整洁的代码。
这是我编写的一些代码,用于简化对顶尖学生的查询。
static void Main(string[] args)
{
var lines = System.IO.File.ReadAllLines(@"C:\...\scores.csv")
.ToList();
var scores = lines.Skip(1)
.Select(l =>
{
var split = l.Split(',');
return new { student = split[1].Trim(),
score = Int32.Parse(split[3].Trim()) };
});
var orderedStudents = scores.GroupBy(s => s.student)
.OrderByDescending(g => g.Average(s => s.score));
var topStudent = orderedStudents.First();
Console.WriteLine("{0} has the top scores with {1}",
topStudent.Key, topStudent.Average(s => s.score));
Console.ReadKey(true);
}