C# 将列表中拆分金额的组合与指定金额匹配
我创建了一个自动化系统,将csv文件中的详细付款与数据库中存储的内容进行匹配 报告金额和DB金额可能并不总是一对一的关系(没有可匹配的键值(它是复合键、CustNum、PaymentType、PaymentDate、PaymentTime)-我从csv文件中获得的唯一信息是CustNum、PaymentType、PaymentDate和amount)。数据库和报告是固定的,不能更改 csv文件来自对基于windows的系统的Web服务调用,DB信息存储从大型机提取的信息 CSV报告基于windows的系统尚未收到付款处理确认的付款。没有收到确认的原因可能有很多,因为中间有许多系统,每个系统都有自己的特性 示例报告:C# 将列表中拆分金额的组合与指定金额匹配,c#,sql,C#,Sql,我创建了一个自动化系统,将csv文件中的详细付款与数据库中存储的内容进行匹配 报告金额和DB金额可能并不总是一对一的关系(没有可匹配的键值(它是复合键、CustNum、PaymentType、PaymentDate、PaymentTime)-我从csv文件中获得的唯一信息是CustNum、PaymentType、PaymentDate和amount)。数据库和报告是固定的,不能更改 csv文件来自对基于windows的系统的Web服务调用,DB信息存储从大型机提取的信息 CSV报告基于windo
|---------------------|------------------|------------------|------------------|
| CustNum | PaymentType | PaymentDate | Amount |
|---------------------|------------------|------------------|------------------|
| 001 | Electronic | 2020-04-01 | 500.00 |
|---------------------|------------------|------------------|------------------|
| 002 | Electronic | 2020-04-01 | 2005.23 |
|---------------------|------------------|------------------|------------------|
| 003 | Electronic | 2020-04-01 | 387.25 |
|---------------------|------------------|------------------|------------------|
|---------------------|------------------|------------------|------------------|
| CustNum | PaymentType | PaymentDate | Amount |
|---------------------|------------------|------------------|------------------|
| 001 | Electronic | 2020-04-01 | 500.00 |
|---------------------|------------------|------------------|------------------|
| 002 | Electronic | 2020-04-01 | 2005.23 |
|---------------------|------------------|------------------|------------------|
| 003 | Electronic | 2020-04-01 | 387.25 |
|---------------------|------------------|------------------|------------------|
示例数据库行:
|---------------------|------------------|------------------|------------------|
| CustNum | PaymentType | PaymentDate | Amount |
|---------------------|------------------|------------------|------------------|
| 001 | Electronic | 2020-04-01 | 500.00 |
|---------------------|------------------|------------------|------------------|
| 002 | Electronic | 2020-04-01 | 2000.00 |
|---------------------|------------------|------------------|------------------|
| 002 | Electronic | 2020-04-01 | 5.23 |
|---------------------|------------------|------------------|------------------|
| 003 | Electronic | 2020-04-01 | 387.25 |
|---------------------|------------------|------------------|------------------|
| 003 | Electronic | 2020-04-01 | 147.51 |
|---------------------|------------------|------------------|------------------|
|---------------------|------------------|------------------|------------------|
| CustNum | PaymentType | PaymentDate | Amount |
|---------------------|------------------|------------------|------------------|
| 001 | Electronic | 2020-04-01 | 500.00 |
|---------------------|------------------|------------------|------------------|
| 002 | Electronic | 2020-04-01 | 2000.00 |
|---------------------|------------------|------------------|------------------|
| 002 | Electronic | 2020-04-01 | 5.23 |
|---------------------|------------------|------------------|------------------|
| 002 | Electronic | 2020-04-01 | 10870.00 |
|---------------------|------------------|------------------|------------------|
| 002 | Electronic | 2020-04-01 | 549.84 |
|---------------------|------------------|------------------|------------------|
| 003 | Electronic | 2020-04-01 | 387.25 |
|---------------------|------------------|------------------|------------------|
| 003 | Electronic | 2020-04-01 | 147.51 |
|---------------------|------------------|------------------|------------------|
我首先对给定的CustNum、RecordType、PaymentDate的所有记录的金额字段求和,并将其与csv上报告的金额进行比较。如果没有匹配,我会尝试匹配各个付款金额,而不是求和。这种方法更有效,因为与直接的一对一关系支付相比,分割支付似乎更多。拆分付款是指数据库保存一次付款的多条记录,但汇总后给出报告的金额
这适用于上述示例中的大多数情况,但有一种情况不适用,即对于给定的CustNum、RecordType和付款日期,DB中存在多笔分割付款
示例报告:
|---------------------|------------------|------------------|------------------|
| CustNum | PaymentType | PaymentDate | Amount |
|---------------------|------------------|------------------|------------------|
| 001 | Electronic | 2020-04-01 | 500.00 |
|---------------------|------------------|------------------|------------------|
| 002 | Electronic | 2020-04-01 | 2005.23 |
|---------------------|------------------|------------------|------------------|
| 003 | Electronic | 2020-04-01 | 387.25 |
|---------------------|------------------|------------------|------------------|
|---------------------|------------------|------------------|------------------|
| CustNum | PaymentType | PaymentDate | Amount |
|---------------------|------------------|------------------|------------------|
| 001 | Electronic | 2020-04-01 | 500.00 |
|---------------------|------------------|------------------|------------------|
| 002 | Electronic | 2020-04-01 | 2005.23 |
|---------------------|------------------|------------------|------------------|
| 003 | Electronic | 2020-04-01 | 387.25 |
|---------------------|------------------|------------------|------------------|
示例数据库行:
|---------------------|------------------|------------------|------------------|
| CustNum | PaymentType | PaymentDate | Amount |
|---------------------|------------------|------------------|------------------|
| 001 | Electronic | 2020-04-01 | 500.00 |
|---------------------|------------------|------------------|------------------|
| 002 | Electronic | 2020-04-01 | 2000.00 |
|---------------------|------------------|------------------|------------------|
| 002 | Electronic | 2020-04-01 | 5.23 |
|---------------------|------------------|------------------|------------------|
| 003 | Electronic | 2020-04-01 | 387.25 |
|---------------------|------------------|------------------|------------------|
| 003 | Electronic | 2020-04-01 | 147.51 |
|---------------------|------------------|------------------|------------------|
|---------------------|------------------|------------------|------------------|
| CustNum | PaymentType | PaymentDate | Amount |
|---------------------|------------------|------------------|------------------|
| 001 | Electronic | 2020-04-01 | 500.00 |
|---------------------|------------------|------------------|------------------|
| 002 | Electronic | 2020-04-01 | 2000.00 |
|---------------------|------------------|------------------|------------------|
| 002 | Electronic | 2020-04-01 | 5.23 |
|---------------------|------------------|------------------|------------------|
| 002 | Electronic | 2020-04-01 | 10870.00 |
|---------------------|------------------|------------------|------------------|
| 002 | Electronic | 2020-04-01 | 549.84 |
|---------------------|------------------|------------------|------------------|
| 003 | Electronic | 2020-04-01 | 387.25 |
|---------------------|------------------|------------------|------------------|
| 003 | Electronic | 2020-04-01 | 147.51 |
|---------------------|------------------|------------------|------------------|
在上述示例中,2005.23的CustNum 002的报告金额不会报告为匹配金额,因为对于指定的CustNum和PaymentType,该金额既不是单一付款,也不是自该付款日期起的所有付款的总和
我认为我需要做的是从DB中查找所有的金额组合,并将这些组合与报告的值进行比较,以确定是否有任何值匹配。但如果有人有更好的解决方案,我愿意改变
以上是一个简化的示例-DB在指定的PaymentDate上,每个客户可能有10或20笔与PaymentType匹配的分割付款
考虑到我掌握的信息有限,以及报告的付款方式,我不确定最好的方法是什么
非常感谢您在这方面提供的任何指导。对于暴力法,您可以从数据库计算所有金额组合,并查找是否有与CSV文件金额匹配的金额。假设一旦被其他字段过滤,金额的数量很小,这不应该太慢: 使用这些扩展方法:
public static bool IsEmpty<T>(this IEnumerable<T> src) => !src.Any();
public static IEnumerable<IEnumerable<T>> AllCombinations<T>(this IEnumerable<T> start) {
IEnumerable<IEnumerable<T>> HelperCombinations(IEnumerable<T> items) {
if (items.IsEmpty())
yield return items;
else {
var head = items.First();
var tail = items.Skip(1);
foreach (var sequence in HelperCombinations(tail)) {
yield return sequence; // Without first
yield return sequence.Prepend(head);
}
}
}
return HelperCombinations(start).Skip(1);
}
对于蛮力方法,您可以从数据库计算所有金额组合,并查找是否有与CSV文件金额匹配的金额。假设一旦被其他字段过滤,金额的数量很小,这不应该太慢: 使用这些扩展方法:
public static bool IsEmpty<T>(this IEnumerable<T> src) => !src.Any();
public static IEnumerable<IEnumerable<T>> AllCombinations<T>(this IEnumerable<T> start) {
IEnumerable<IEnumerable<T>> HelperCombinations(IEnumerable<T> items) {
if (items.IsEmpty())
yield return items;
else {
var head = items.First();
var tail = items.Skip(1);
foreach (var sequence in HelperCombinations(tail)) {
yield return sequence; // Without first
yield return sequence.Prepend(head);
}
}
}
return HelperCombinations(start).Skip(1);
}
我认为您没有提供足够的详细信息-CSV文件来自哪里?为什么它只包含同一日期的一些交易(分割付款)?我会用信息更新问题。我认为你没有提供足够的详细信息-CSV文件来自哪里?为什么它只包含同一日期的一些交易(分割付款)?我会用信息更新这个问题。谢谢。我要试试这个。到目前为止,我所看到的最多的情况是,在给定的paymentDate上,对于paymentType,每个客户大约有20笔分割付款,这是很少见的,通常情况下,这些场景中只有4到6笔。如果我理解正确,那么如果数据库只有一条记录,这也会起作用。所以我可以替换前两个检查,只做这个检查。@gheff是的,如果只有一个数据库记录在
数量中,这将起作用。这非常有效。我只需要做两个改变。我使用的是.Net 4.5.2,所以我需要编写自己的Prepend方法,第二个方法是不要跳过初始HelperCombinations调用中的第一条记录,因为在DB调用中没有返回头。我的错误是将其包含在示例中。很抱歉,由于我使用的是.net 4.5.2和visual studio 2017,因此需要进行额外编辑,以取消嵌套HelperCombinations方法。VisualStudio不喜欢它。我想这项功能是在后来的一次会议上引入的version@gheffreturn
中的Skip(1)
用于跳过从递归方法返回的第一个空IEnumerable
。谢谢。我要试试这个。到目前为止,我所看到的最多的情况是,在给定的paymentDate上,对于paymentType,每个客户大约有20笔分割付款,这是很少见的,通常情况下,这些场景中只有4到6笔。如果我理解正确,那么如果数据库只有一条记录,这也会起作用。所以我可以替换前两个检查,只做这个检查。@gheff是的,如果只有一个数据库记录在数量中,这将起作用。这非常有效。我只需要做两个改变。我使用的是.Net 4.5.2,所以我需要编写自己的Prepend方法,第二个方法是不要跳过初始HelperCombinations调用中的第一条记录,因为在DB调用中没有返回头。我的错误是将其包含在示例中。很抱歉,由于我使用的是.net 4.5.2和visual studio 2017,因此需要进行额外编辑,以取消嵌套HelperCombinations方法。VisualStudio不喜欢它。我想这项功能是在后来的一次会议上引入的version@gheffreturn
中的Skip(1)
用于跳过空的IEnumerable
,这是递归方法的第一次返回。