在单个 linq 查询中列出列表

list in list in a single linq query

我有这个 csv

Id Name Age
1 Alex 20
1 Maria 16

我想制作一个 CSV Reader 来拆分元素 headerdata 中的 csv。 Header 只是一个字符串数组,保存了 headers 并且运行良好。

我在保存 data 时遇到了问题。我想将 csv 保存在没有 headers 的列表列表中,这就是我这样做的方式:

                var predata = file
                    .Skip(1)
                    .ToList();

                List<List<string>> data = new List<List<string>>();

                for (int i = 0; i < predata.Count; i++)
                {
                    List<string> templist = predata[i]
                        .Split(';')
                        .ToList();

                    data.Add(templist);
                }

这看起来效率很低,我想知道是否有任何方法可以做到这一切,但要短得多。甚至可能在一个 linq 查询中。

请不要报告这个问题,我会尽力解释我的问题

试试这个:

var data=file.select(x=>x.Split(';').ToList()).ToList();

当然 - 只需使用 .Select:

var data = predata.Select(p = > p.Split(';'));

这实际上会为您提供一个 IEnumerable<string[]>,您可以对其进行迭代。如果您需要 个列表,只需在每个级别添加 ToList

var data = predata.Select(p = > p.Split(';').ToList()).ToList();

并且您可以跳过 predata,只需将其更改为 file.Skip(1)(如果您所做的只是迭代,则无需在 Skip 之后调用 ToList ).

为了提高性能和缩短代码,我们可以做的一件大事是避免比需要更频繁地调用 .ToList()。事实上,如果你可以接受 IEnumerable<string[]> 而不是 List<List<string>> 我们可以把它归结为这个,这也应该 运行 更快并且分配 MUCH内存:

var data = file.Skip(1).Select(line => line.Split(';'));

如果你真的必须List<List<string>>我们可以调整如下:

var data = file.Skip(1).Select(line => line.Split(';').ToList()).ToList();

但同样:每次调用 .ToList() 都会增加更多 RAM 并 CPU 使用您的程序。最好等待尽可能长的时间。


我也很好奇 file 变量是从哪里来的。这似乎是 File.ReadAllLines()File.ReadLines() 的结果,我可以告诉你,后者将再次比前者更有效 MUCH

所以你想要这样的东西:

var header = File.ReadLines("...").Take(1);
var data = File.ReadLines("...").Skip(1).Select(line => line.Split(';'));

此时请注意data 尚未通读文件。但是,您可以在 foreach 循环中或使用 linq 扩展名使用它,它将以 just-in-time 方式读取文件,这样内存中一次只需要文件中的一行时间。

这样效率更高,即使您最终会在屏幕上显示整个文件内容或以其他方式完全加载文件,因为它可以节省 RAM(和 CPU) 同时将文件中的原始数据转换为您想要显示或其他目的的最终结构。


除了所有这些之外,您可以做的事情 真正 提高性能是从 NuGet 获得专用的 csv 解析器,特别是因为 .Split() 被认为是一个在许多边缘情况下速度稍慢并且失败。