C# 是否可以更改LINQ中的搜索方法?

C# 是否可以更改LINQ中的搜索方法?,c#,linq,csv,C#,Linq,Csv,我有30000行的csv文件。我必须根据许多条件选择许多值,因此我决定使用linq来代替许多循环和“if”。我写了一节阅读csv的课。它实现了用于linq的IEnumerable。这是我的统计员: class CSVEnumerator : IEnumerator { private CSVReader _csv; private int _index; public CSVEnumerator(CSVReader csv) { _csv =

我有30000行的csv文件。我必须根据许多条件选择许多值,因此我决定使用linq来代替许多循环和“if”。我写了一节阅读csv的课。它实现了用于linq的IEnumerable。这是我的统计员:

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;
    }

}
CSVEnumerator类:IEnumerator
{
私人CSVReader_csv;
私有整数指数;
公共CSVEnumerator(CSVReader csv)
{
_csv=csv;
_指数=-1;
}
public void Reset(){u index=-1;}
公共对象流
{
得到
{
返回新的CSVRow(_索引,_csv);
}
}
公共图书馆
{
返回++\u索引<\u csv.TotalRows;
}
}
它在工作,但速度很慢。假设我想在A列中选择范围为100的最大值;150排

max  = (from CSVRow r in csv where r.ID > 100 && r.ID < 150 select r).Max(y=>y["A"]);
max=(从csv中的CSVRow r开始,其中r.ID>100&&r.ID<150选择r)。max(y=>y[“A”);
这将起作用,但linq在30000行中搜索最大值,而不是48行。 正如我所说,我可以使用循环,但只有在本例中,条件是“残酷的”:

是否有任何方法可以覆盖linq集合搜索。类似于:查看在我的枚举器上使用的查询,查看“where”中的任何linq条件是否包含“row ID filter”,并基于此给出另一个数据

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

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

max = csv.Skip(100).Take(50).Max(y => y["A"]);

@DougM关于求值顺序的看法是正确的,但在本例中,我要做的是一次性初始化并生成任何“索引”字段的查找:基本上,预先计算行索引到行的映射(字典)。也就是说,只有在对给定的索引字段有许多重复查询时,这才有用。

如果您希望能够有效地使用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);
    }
}

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

顺便说一句,你应该实现
IEnumerable
。这是如何实现的->
新的CSVRow(\u index,\u csv)
。随机存取还是顺序存取?您确定linq to objects将Max应用于您的所有记录,而不仅仅是这些记录吗?奇怪的是,它应该按顺序应用运算符。我的猜测是你的枚举器太慢了。问题可能是这里没有实现的读取器。试着只读取一次完整的文件,然后处理它。Wiktor:对不起,我误解了你的问题,你是对的,max只在48行上完成,但要获得它们,它必须搜索所有30k行。读卡器接受索引访问,所以如果索引大于100,搜索100行是无效的,如果索引小于150,搜索30k-150行是无效的,但这仍然会迭代150行,即50行。因此,如果范围是29000-29050,您将迭代29050行,这是非常无效的。@svik:如果您跳过前29000行,您的CSVReader如何知道他在哪一行?您仍然需要在阅读之前阅读所有内容,以便选择正确的行。我猜CSVReader的实现效率很低。它应该缓存已经读取的行,然后几乎所有的查询都会很快。@AloisKraus我不知道
CSVReader
是如何实现的,但问题是,它可以高效地检索任何一行。由于CSV文件没有索引,因此无法跳过行并跟踪跳过了多少行,除非输入格式为固定宽度,或者id列确实提供了顺序,您可以通过二进制搜索找到匹配行。我不认为实施的效率如此之高,以至于光盘读取速度将成为限制因素。但对于30000行,我只需要一次读取并处理它。我同意跳过的对象越多(在本例中是行),性能就会下降。然而,我认为在更智能的CSVReader实现中解决这个问题会更好。我相信这就是@JerKimball所指的。这正是我所需要的,谢谢:-)100和150是唯一能说明问题的例子,如果我发布真实条件,我必须解释变量来自何处,哪些数据类型等。。。
max = csvReader.GetRows(100, 150).Max(y => y["A"]);