由于字符串比较导致文档号计算不正确

本文关键字:文档 计算 不正确 字符串 比较 | 更新日期: 2023-09-27 18:02:29

    我有一个要评估的文档编号列表。这个列表非常大,我不想将所有文档号都强制转换为int型,因为它们也可能包含字母。以下是一个示例数字列表。

1070
1071
1072
1073
1074
1075
1076
1077
1078
CO1089
CO1099
CO2000

    这些数字包含在c#的对象中,我运行Linq来返回Range中的对象列表。这是我的linq代码。

results = from row in MyObjectList.AsQueryable<MyObject>()
          where String.Compare(row.Header.DocNumber, _sDocumentStartNumber) >= 0 
          && String.Compare(row.Header.DocNumber, _sDocumentEndNumber) <= 0
          select row;
如果我有一个范围

: 1
: ,,,,, 10000,

    用户希望返回该范围内所有数字编号的事务。然而,因为我比较字符串,我没有得到任何结果。

    我可以检测到我的to和from值是数字,然后只计算与数字有关的事务,并在此基础上使用linq语句(或编辑linq语句来进行转换和比较),但此时我关心的是性能,因为返回时列表可能相当大。

    我愿意听取建议,也知道可能有很多途径都通向同样的结果。我最关心的是性能。请记住,我可以在非常大的数据集上执行此操作,并且我需要在合理的时间内返回结果。

提前感谢您的任何建议。

~~~编辑

    我利用的对象是Intuit IPP SDK对象QuickBooks Online。我正在直观地查询文档(如发票),并且需要对文档编号进行排序。Intuit没有在他们的服务器端做这个,所以我必须在我的服务器端做这个。根据用户输入的其他搜索条件,我可以在返回的列表中得到他们所有的文档。

由于字符串比较导致文档号计算不正确

创建自己的比较器,例如DocumentNumberWithinRangeComparer:

public class DocumentNumberWithinRangeComparer
{
    public int? RangeFrom { get; set; }
    public int? RangeTo { get; set; }
    public DocumentNumberWithinRangeComparer(int? from, int? to)
    {
        RangeFrom = from;
        RangeTo = to;
    }
    public bool IncludeInResults(MyObject obj)
    {
        if (!RangeTo.HasValue || !RangeFrom.HasValue)
            return true;
        int docnumber;
        if (!Int32.TryParse(obj.Header.DocNumber, out docnumber))
            return false;
        return docnumber >= RangeFrom.Value && docnumber <= RangeTo.Value;
    }
}

然后创建一个实例并使用它来过滤:

var comparer = new DocumentNumberWithinRangeComparer(0,100);
var results = from row in MyObjectList.AsQueryable<MyObject>()
              where comparer.IncludeInResults(row)
              select row;

如果你想要更快的比较,你应该预处理你的"DocNumber"为整数,但这只有在你处理一次文档列表然后多次查询它时才有意义。


预处理的一个简单解决方案是从Header.DocNumber字符串值和解析的数字值创建Dictionary<string, int>。对于不能解析的值,可以使用-1Int32.MinValue之类的东西,或者使用更高级的解析器来处理非数值。

一旦你有了字典,你可以像这样查询…

var dictionary = new Dictionary<string, int>(); // Fill this...
var results = from row in MyObjectList.AsQueryable<MyObject>()
              where dictionary[row.Header.DocNumber] >= _sDocumentStartNumber &&
                    dictionary[row.Header.DocNumber] <= _sDocumentEndNumber 
              select row;

设置这个字典将花费一些额外的时间,但是如果您多次查询同一个文档集,这将是值得的。

当您获得范围时,用空格左填充开始数字,使其与结束数字相同的长度。在你的例子中,你的结束数字是"10000"。因此,将您的起始数字设置为"__1"(即4个空格,然后一个1)。

比较时,在比较前左加文档号。所以:

string paddedStart = _sDocumentStartNumber.PadLeft(_sDocumentEndNumber.Length);
string padded;
results = from row in MyObjectList.AsQueryable<MyObject>()
      let padded = row.Header.DocNumber.PadLeft(paddedStart.Length)
      where String.Compare(padded, paddedStart) >= 0 
          && String.Compare(padded, _sDocumentEndNumber) <= 0
      select row;