6

我有 30 000 行的 csv 文件。我必须根据许多条件选择许多值,因此插入了许多循环和“if”我决定使用 linq。我已经写了类来阅读 csv。它实现了 IEnumerable 以与 linq 一起使用。这是我的枚举器:

class CSVEnumerator : IEnumerator
{

    private CSVReader _csv;

    private int _index;

    public CSVEnumerator(CSVReader csv)
    {
        _csv = csv;
        _index = -1;
    }

    public void Reset(){_index = -1;}


    public object Current
    {
        get
        {
            return new CSVRow(_index,_csv);
        }
    }


    public bool MoveNext()
    {
        return ++_index < _csv.TotalRows;
    }

}

它正在工作,但速度很慢。假设我想在 100;150 行范围内的 A 列中选择最大值。

max  = (from CSVRow r in csv where r.ID > 100 && r.ID < 150 select r).Max(y=>y["A"]);

这将起作用,但是 linq 在 30 000 行而不是 48 行中搜索最大值。正如我所说,我可以使用循环,但仅在本例中,条件是“残酷的”:)

有没有办法覆盖 linq 集合搜索。类似于:查看我的枚举器上使用的查询,查看“where”中的任何 linq 条件是否包含“行 ID 过滤器”并基于此提供另一个数据。

我不想将部分数据复制到另一个数组/集合,问题不在我的 csv 阅读器中。通过 id 访问每一行很快,唯一的问题是当您访问所有 30 000 行时。任何帮助appriciated :-)

4

3 回答 3

2

如果您希望能够有效地使用 LINQ,则需要使用表达式树,其方式与 SQL 数据库的各种 LINQ 提供程序类似(但更简单)。虽然可行,但我认为对于这样一个简单的任务将是相当多的代码。

因此,我认为更好的解决方案是使用单独的方法来选择您想要的行(然后可能使用 LINQ 来处理结果)。

此外,许多返回集合的操作(包括您的原始代码和我的修改)可以通过使用迭代器方法来简化。

因此,您的代码可能如下所示:

public static IEnumerable<CSVRow> GetRows(
    this CSVReader reader, int idGreaterThan, int idLessThan)
{
    for (int i = idGreaterThan + 1; i < idLessThan; i++)
    {
        yield return new CSVRow(reader, i);
    }
}

在这里,它是 的扩展方法CSVReader,但另一种解决方案(例如,该类的实际方法)可能更适合您。

您的示例将类似于:

max = csvReader.GetRows(100, 150).Max(y => y["A"]);

(另外,我觉得奇怪的是,当你有 100 和 150 的限制时,你实际上想要 101 和 149 之间的行。但我假设你有这样做的理由,所以我也这样做了。)

于 2013-01-01T01:05:27.583 回答
1

就 LINQ 而言,r.ID 只是一个被过滤的值,因此所有 30k 行都被考虑用于 Max 操作。如果这是一个行索引,这似乎是这里的情况,您可以使用 Skip 和 Take 来避免比较所有 30k 行。

max = csv.Skip(100).Take(50).Max(y => y["A"]);
于 2013-01-01T00:01:57.317 回答
0

@DougM 关于评估的顺序是正确的,但在这种情况下,我要做的是对初始化进行一次点击并为任何“索引”字段生成查找:基本上,预先计算行索引到行的映射(字典) . 也就是说,这仅在您对给定索引字段有许多重复查询时才有用。

于 2013-01-01T00:12:12.670 回答