gpt4 book ai didi

c# - LINQ:大字符串列表

转载 作者:太空狗 更新时间:2023-10-30 00:15:27 26 4
gpt4 key购买 nike

我正在使用 LINQ 来解析从 csv 文件读取的大量字符串。我的代码适用于 100MB 的文件。但由于堆栈溢出异常无法超越它。我正在用 500MB 的文件测试我的代码,其中列表中的字符串数约为 400 万。(500MB 的 csv 文件中大约有 400 万行)

    public List<Metrics> MetricsParser(DateTime StartDate, TimeSpan StartTime, DateTime EndDate, TimeSpan EndTime,int dateIndex,int timeIndex)
{
DateTime sd = StartDate;
DateTime ed = EndDate;
TimeSpan st = StartTime;
TimeSpan et = EndTime;
StreamReader streamReader;
List<string> lines = new List<string>();


try
{
streamReader = new StreamReader("file.csv");
lines.Clear();
while (!streamReader.EndOfStream)
lines.Add(streamReader.ReadLine());
}
catch (Exception ex)
{
throw ex;
}
finally
{
if (streamReader != null)
streamReader.Close();
}

IEnumerable<Metrics> parsedFileData = null;
parsedFileData = from line in lines
let log = line.Split(",")
where (!(line.StartsWith("#")) & (line.Length > 0))
let dateVal = _utility.GetDateTime(dateformatType, log[(int)dateIndex], log[(int)timeIndex])
let timeVal = _utility.GetTime(log[(int)timeIndex], timeformatType)
where (dateVal >= new DateTime(sd.Year, sd.Month, sd.Day, st.Hours, st.Minutes, st.Seconds)
& dateVal <= new DateTime(ed.Year, ed.Month, ed.Day, et.Hours, et.Minutes, et.Seconds))
select new Metrics()
{
Date = dateVal,
Metrics1 = log[(int)Metrics1Index],
Metrics2 = (Metrics2Index != null) ? log[(int)Metrics2Index] : "default",
Metrics3 = (log[(int)Metrics3Index] == null || log[(int)Metrics3Index] == "") ? "-" : log[(int)Metrics3Index],
Metrics4 = (log[(int)Metrics4Index] == null || log[(int)Metrics4Index] == "") ? "-" : log[(int)Metrics4Index],
Metrics5 = (log[(int)Metrics5Index] == null || log[(int)Metrics5Index] == "") ? "-" : log[(int)Metrics5Index],
Metrics6 = (log[(int)Metrics6Index] == null || log[(int)Metrics6Index] == "") ? "-" : log[(int)Metrics6Index],
Metrics7 = (log[(int)Metrics7Index] == null || log[(int)Metrics7Index] == "") ? "-" : log[(int)Metrics7Index],
Metrics8 = (log[(int)Metrics8Index] == null || log[(int)Metrics8Index] == "") ? "-" : log[(int)Metrics8Index],
Metrics9 = (log[(int)Metrics9Index] == null || log[(int)Metrics9Index] == "") ? "-" : log[(int)Metrics9Index],
};
return parsedFileData.ToList();
}

关于如何用更大的数据完成任务的任何想法。

我按照一些建议进行了如下尝试,但它也无法克服堆栈溢出异常!

try
{
streamReader = new StreamReader("file.csv");
while (!streamReader.EndOfStream)
{
var line = streamReader.ReadLine();
if (!(line.StartsWith("#")) & (line.Length > 0))
{
var log = line.Split(",");
var dateVal = _utility.GetDateTime(dateformatType, log[(int)dateIndex], log[(int)timeIndex]);
parsedData.Add(
new Metrics()
{
Date = dateVal,
Metrics1 = log[(int)Metrics1Index],
Metrics2 = (Metrics2Index != null) ? log[(int)Metrics2Index] : "default",
Metrics3 = (log[(int)Metrics3Index] == null || log[(int)Metrics3Index] == "") ? "-" : log[(int)Metrics3Index],
Metrics4 = (log[(int)Metrics4Index] == null || log[(int)Metrics4Index] == "") ? "-" : log[(int)Metrics4Index],
Metrics5 = (log[(int)Metrics5Index] == null || log[(int)Metrics5Index] == "") ? "-" : log[(int)Metrics5Index],
Metrics6 = (log[(int)Metrics6Index] == null || log[(int)Metrics6Index] == "") ? "-" : log[(int)Metrics6Index],
Metrics7 = (log[(int)Metrics7Index] == null || log[(int)Metrics7Index] == "") ? "-" : log[(int)Metrics7Index],
Metrics8 = (log[(int)Metrics8Index] == null || log[(int)Metrics8Index] == "") ? "-" : log[(int)Metrics8Index],
Metrics9 = (log[(int)Metrics9Index] == null || log[(int)Metrics9Index] == "") ? "-" : log[(int)Metrics9Index],
}
);
}

}
}

谢谢你的想法!

最佳答案

尝试逐行解析文件,而不是像这样保存到内存中

var parsedFileData = new List<Metrics>();

while (!streamReader.EndOfStream)
{
var line = streamReader.ReadLine();

if(IsLineNeedToBeParsed(line))
parsedFileData.Add(ParseLine(line));
}

ParseLine 是方法,它包含 LINQ 查询的内容,但在单行上运行,IsLineNeedToBeParsed 是您的 where 子句。 .正如我所注意到的-您没有进行任何行的连接。

避免加载整个文件内容,然后使用大量 let 子句执行一些大型查询 - 它会在执行期间消耗大量内存。

尝试创建过滤、选择聚合数据的纯函数,然后,如果您仍然不喜欢性能,请尝试通过添加状态、消除冗余计算、可能缓存、添加批处理等来优化查询。

一个快速的要点:你应该让文件加载延迟,就像这样:

private IEnumerable<string> GetAllLines(string path)
{
using (StreamReader streamReader = new StreamReader(path))
{
while (!streamReader.EndOfStream)
{
yield return streamReader.ReadLine();
}
}
}

然后您可以从 LINQ 查询中调用它

from line in GetAllLines("file.csv")

并且所有行都将按需加载,并且您的内存消耗在执行期间应该相对恒定。

更新:

我刚刚发现,File.ReadLines(string path) 通过在内部创建 ReadLinesIterator 来延迟读取文件。因此,您可以在 LINQ 查询中使用此调用。

我鼓起勇气稍微重构了您的代码。请注意,您仍然需要添加一些检查,这不是最终版本 - 我只是想展示总体思路。另请注意,我还没有编译它——因为您可以访问解析器状态,而我对它的类型和值一无所知。代码比你的长一点,但我永远不会忘记 Robert Martin 的 Clean Code book,它有一个重要的观点“不是短,而是使代码可读”。如果我在某个地方错了,请纠正我。

public List<Metrics> MetricsParser(DateTime StartDate, TimeSpan StartTime, DateTime EndDate, TimeSpan EndTime,int dateIndex,int timeIndex)
{
DateTime sd = StartDate;
DateTime ed = EndDate;
TimeSpan st = StartTime;
TimeSpan et = EndTime;
List<Metrics> parsedFileData = new List<Metrics>();

using (StreamReader streamReader = new StreamReader("file.csv"))
{
while (!streamReader.EndOfStream)
{
var line = streamReader.ReadLine();

if(IsLineNeedToBeParsed(line))
parsedFileData.Add(ParseLine(line));
}
}

return parsedFileData;
}

private bool IsLineNeedToBeParsed(string line)
{
return !(line.StartsWith("#")) && (line.Length > 0) && IsInDateRange(line);
}

private bool IsInDateRange(string line)
{
var dateVal = GetDateTime(line);
return dateVal >= new DateTime(sd.Year, sd.Month, sd.Day, st.Hours, st.Minutes, st.Seconds)
& dateVal <= new DateTime(ed.Year, ed.Month, ed.Day, et.Hours, et.Minutes, et.Seconds);
}

private Metrics ParseLine(string line)
{
var log = line.Split(',');
var time = _utility.GetTime(log[(int)timeIndex], timeformatType);
var dateVal = GetDateTime(line);
return new Metrics{ /* fill values here */ }
}

private string[] GetDateTime(string line)
{
var log = line.Split(',');
return _utility.GetDateTime(dateformatType, log[(int)dateIndex], log[(int)timeIndex]);
}

public class Metrics{}

关于c# - LINQ:大字符串列表,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14376512/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com