0

我创建了mod10算法的 LINQ 实现。

源代码:

string number = "7992739871";
int mod10sum = number.Reverse()
    .Select((c, i) => (c - '0') << ((i + 1) & 1)) // Double every other digit and sum the digits of the products (e.g., 10: 1 + 0 = 1, 14: 1 + 4 = 5) 
    .Sum(c => c - '0') % 10;                      // together with the undoubled digits from the original number

string checkDigit = (mod10sum == 0 ? 0 : 10 - mod10sum).ToString("0");
Console.WriteLine(checkDigit);

根据示例7992739871数字应具有校验位3;但是,我得到的是15.

我做错了什么?我确信错误很小但找不到。

4

2 回答 2

7

问题出在Select方法上。为了总结所有数字(如算法中所述),您需要返回1and0而不是1014不是14(如您的示例中所示)。

简单但不一定是最佳)的方法是将数字从(14 -> "14")Select转换为string(14 -> "14"),然后使用SelectMany.

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

int mod10sum = number.Reverse()
    .SelectMany((c, i) => ((c - '0') << ((i + 1) & 1)).ToString())
    .Sum(c => c - '0') % 10;

checkDigit = (mod10sum == 0 ? 0 : 10 - mod10sum).ToString("0");
Console.WriteLine(checkDigit);

一点理论

LINQ SelectMany返回IEnumerable<>. 当您返回string(即 IEnumerable)时,这就是为什么SelectMany将返回的字符串“拆分”为字符的原因。

Microsoft 有非常好的页面(101 LINQ Samples),其中包含不同的 LINQ 示例,应该可以帮助您。

编辑

我还建议进行从int到的转换string。昨天我正在从事类似的项目,就我而言,从性能的角度来看,转换有点问题,因为我们将这种方法称为数百万次。如果您必须计算大量 mod10,那么它可能不是最佳解决方案。

于 2013-01-09T12:50:55.053 回答
2

我会改变Sum.

此时,您没有字符序列,而是每个原始数字的单倍或双倍值。

因此,您不需要减去0,您需要计算每个整数的数字总和,并且(因为您知道它们会很小)您可以简单地执行此操作

.Sum(i => (i % 10) + (i / 10))

给予

string number = "7992739871";
int mod10sum = number.Reverse()
    .Select((c, i) => (c - '0') << ((i + 1) & 1)) 
    .Sum(i => (i % 10) + (i / 10)) % 10;

这应该比调用ToString()和迭代结果更有效。

于 2013-01-09T13:00:43.983 回答