我有以下Linq查询。 transactionData是一个IEnumerable。
var totalTransactions = 0;
viewModel.GroupedTransactions = transactionData
.GroupBy(x => new { DocumentId = x.DocumentId ?? "Un Documented" })
.Select(x => new GroupedTransaction
{
DocumentId = x.Key.DocumentId,
Transactions = x.Select(y => new Transaction
{
Amount = y.CommitAmount,
ActivityType = y.ActivityType,
Number = totalTransactions++
})
})
.OrderBy(x => x.DocumentId);
我试图将交易记录上的数字设置为递增数字。 这不起作用,留下数字上的空白。
我在查询后也尝试了以下内容。
foreach (var item in viewModel.GroupedTransactions.SelectMany(x => x.Transactions))
{
item.Number = totalTransactions;
totalTransactions++;
}
这甚至没有更新Number值。 我做错了什么,或者有一种更简单的方法,使用简洁的linq扩展方法?
答案 0 :(得分:1)
问题是您要关闭变量totalTransactions
,您必须创建要使用的本地副本。 Check Closing over the loop variable considered harmful有更详细的解释。
这样的事情应该有效:
var totalTransactions = 0;
viewModel.GroupedTransactions = transactionData
.GroupBy(x => new { DocumentId = x.DocumentId ?? "Un Documented" })
.Select(x =>
{
new GroupedTransaction()
{
DocumentId = x.Key.DocumentId,
Transactions = x.Select(y =>
{
var currentTransactionId = totalTransactions;
totalTransactions++;
return new Transaction
{
Amount = y.CommitAmount,
ActivityType = y.ActivityType,
Number = currentTransactionId
}
})
}
})
.OrderBy(x => x.DocumentId);
对于使用foreach循环的第二种方法 - 您实际上是在创建一个新的枚举,其中SelectMany()
随后就会丢弃:
foreach (var item in viewModel.GroupedTransactions.SelectMany(x => x.Transactions))
{
item.Number = totalTransactions;
totalTransactions++;
}
相反,您必须使用ToList()
来创建可以安全修改的集合,强制对集合进行热切评估。
var transactions = viewModel.GroupedTransactions
.SelectMany(x => x.Transactions)
.ToList();
foreach (var item in transactions)
{
item.Number = totalTransactions;
totalTransactions++;
}
答案 1 :(得分:1)
另一种思考方式是你有两个序列:
你想得到一个序列,有ids的交易。当我们想要组合两个序列时,我们可以使用Zip
运算符:
viewModel.GroupedTransactions = transactionData
.GroupBy(x => new { DocumentId = x.DocumentId ?? "Un Documented" })
.Zip(Enumerable.Range(0, int.MaxValue), (x, index) => new GroupedTransaction
{
DocumentId = x.Key.DocumentId,
Transactions = x.Select(y => new Transaction
{
Amount = y.CommitAmount,
ActivityType = y.ActivityType,
Number = index
})
})
.OrderBy(x => x.DocumentId);
这是你的想法吗?
Zip组合两个序列,直到它到达其中一个序列的末尾。这就是为什么它可以使用Enumberable.Range获得比我们实际需要的更大范围的数字。