如何对同一个数据文件运行多个 LINQ 查询

本文关键字:LINQ 查询 运行 文件 同一个 数据 | 更新日期: 2023-09-27 18:34:54

我是LINQ新手,目前正在使用它来处理csv格式的大型数据集(五十万条记录(。我正在使用StreamReader打开文件并实现IEnumerable<>接口以填充结果。下面您可以看到读取代码的主要部分:

IEnumerator<Person> IEnumerable<Person>.GetEnumerator()
{
    using (StreamReader streamReader = new StreamReader(filename)){
        streamReader.ReadLine();
        while (!streamReader.EndOfStream){
            string[] values = streamReader.ReadLine().Split(new char[] { ',' });
            Person p = new Person();
            p.Name = values[0];
            p.Age = Convert.ToInt16(values[1]);
            p.Score = Convert.ToDouble(values[2]);
            p.PlotArea = Convert.ToInt16(values[3]);
            p.ForecastConsumption = Convert.ToDouble(values[4]);
            p.Postcode = values[5];
            p.PropertyType = values[6];
            p.Bedrooms = Convert.ToInt16(values[7]);
            p.Occupancy = Convert.ToInt16(values[8]);
            yield return p;
        }
    }
}

这是一个典型的查询:

var query = from person in reader
            where person.Score > 36.55 && person.Bedrooms < 3
            select person;

我的问题是,每次我想运行查询时,StreamReader都必须打开文件。有什么方法可以打开文件一次并运行多个查询吗?

仅供参考,我对 LINQ 印象深刻,运行上面的查询需要 1.2 秒。只是我会为数据集运行很多规则。

如何对同一个数据文件运行多个 LINQ 查询

我的问题是,每次我想运行查询时,StreamReader 都必须打开文件。有什么方法可以打开文件一次并运行多个查询吗?

最简单的方法是将整个文件加载到列表中,例如

var list = reader.ToList();
// Now run multiple queries over list

显然,这将占用相当多的内存,但这将是最简单的方法。如果要将多个查询联接在一起,则必须准确确定要执行的操作 - LINQ 中的组合模型主要是将查询操作链接在一起,而不是从同一源生成多个查询。

如果

做不到这一点,如果"一次传递多个查询"和"将整个文件加载到内存中"的复杂性都不适合您,您可能会多次加载它。

一个可能更节省内存的中间选项是将所有行读入内存(因此您只执行一次磁盘活动(,但随后多次解析这些。这在IO方面效率会更高,但在CPU方面会更糟。

这应该有效:

  return from line in File.ReadAllLines(filename)
                     let values = line.Split(new char[] { ',' })
                     select new Person{
                Name = values[0];
                Age = Convert.ToInt16(values[1]);
                Score = Convert.ToDouble(values[2]);
                PlotArea = Convert.ToInt16(values[3]);
                ForecastConsumption = Convert.ToDouble(values[4]);
                Postcode = values[5];
                PropertyType = values[6];
                Bedrooms = Convert.ToInt16(values[7]);
                Occupancy = Convert.ToInt16(values[8]);
            };

您的情况将是以下各项之间的性能权衡:

  1. 将整个文件读入内存,并运行所需的任何查询
  2. 只需多次迭代文件即可。

如果是后者,请尝试使用File.ReadLines,它在文件 IO 上提供了一个很好的 IEnumerable 接口:

public Person ReadPerson(string[] personLine)
{
    Person p = new Person();
    p.Name = personLine[0];
    p.Age = Convert.ToInt16(personLine[1]);
    p.Score = Convert.ToDouble(personLine[2]);
    p.PlotArea = Convert.ToInt16(personLine[3]);
    p.ForecastConsumption = Convert.ToDouble(personLine[4]);
    p.Postcode = personLine[5];
    p.PropertyType = personLine[6];
    p.Bedrooms = Convert.ToInt16(personLine[7]);
    p.Occupancy = Convert.ToInt16(personLine[8]);
}

和用法:

var file = File.ReadLines("/filepath/")
    .Select(line => ReadPerson(line.Split(',')));
var query = from person in file
    where person.Score > 36.55 && person.Bedrooms < 3
    select person;