如何对同一个数据文件运行多个 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 秒。只是我会为数据集运行很多规则。
我的问题是,每次我想运行查询时,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]);
};
您的情况将是以下各项之间的性能权衡:
- 将整个文件读入内存,并运行所需的任何查询
- 只需多次迭代文件即可。
如果是后者,请尝试使用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;