优化Linq查询?

时间:2017-07-12 16:10:37

标签: c# linq csv

我试图从包含以下内容的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);
    }
}

3 个答案:

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