根据另一个int列表填充缺少的值
本文关键字:填充 列表 另一个 int | 更新日期: 2023-09-27 18:20:34
我有一个IEnumerable,其中SaleReport的模型如下:
public int ID { get; set; }
public DateTime StartDate { get; set; }
public DateTime EndDate { get; set; }
public decimal Amount { get; set; }
public SalesReportProduct Product { get; set; }
public int ItemID { get; set; }
public int LanguageID { get; set; }
public int ProductID { get; set; }
我正在用基于dateTime值的数据库条目填充这个IEnumerable:
salesReports = _salesReport.GetAll(fromDate, toDate);
然后我有一个int列表,它是所有可用的ItemID:
var ItemIDList = new List<int>();
我的问题是,我必须插入所有ItemID不在IEnumerable中的SalesReport,因此对于ItemIDList的每个值,我检查IEnumeraable中是否至少有一个对应的ItemID,如果没有,我必须附加一个具有该ItemID的新SalesReport。
我怎样才能轻松做到这一点?
您可以使用Range
&Except
起到了这样的作用。
var unusedIds = Enumerable.Range(1, _salesReport.select(sr => sr.ItemID).Max())
.Except(_salesReport.select(sr => sr.ItemID));
ItemIDList.AddRange(unusedIds);
我不知道Except
函数有多贵,我猜它在_salesReport
中为该范围内的每一项执行Find
。我会查一下然后回复你。
当然我错了Jon Skeets Eudlinq实现的Except
只消耗每个序列一次,ILSpy在.Net源代码中向我展示了类似的优化。
NB:调用Max()
以获得int的范围,当然会在_salesReport
中迭代一次,因此总共会在_salesReport
中迭代两次。
如果这太贵,您可以从_salesReport
缓存ID
var usedIds = _salesReport.select(sr => sr.ItemID).ToList();
var unusedIds = Enumerable.Range(1, usedIds.Max()).Except(usedIds);
ItemIDList.AddRange(unusedIds);
实际上,你可以给自己留一个号码。我们检查列表中是否有Max(),但我们当然知道Max在列表中,因为我们是从列表中得到的,因此我们不需要将Max包括在要检查的数字范围中。
var usedIds = _salesReport.select(sr => sr.ItemID).ToList();
var unusedIds = Enumerable.Range(1, usedIds.Max() - 1).Except(usedIds);
ItemIDList.AddRange(unusedIds);
作为一个练习,我试图以最有效的方式解决这个问题:
var reports = _salesReports.OrderBy(x=>x.ItemId).Select(x=>x.ItemId);
var requiredReports = ItemIdList.OrderBy(x=>x);
int reportsCount = reports.Count();
int requiredCount = requiredReports.Count();
List<int> missingReports = new List<int>();
int reportIndex = 0;
int requiredIndex = 0;
while (reportIndex < reportsCount && requiredIndex < requiredCount)
{
if (reports[reportIndex] == requiredReports[requiredIndex])
{
reportIndex++;
requiredIndex++;
continue;
}
if (reports[reportIndex] < requiredReports[requiredIndex])
{
reportIndex++;
continue;
}
if (reports[reportIndex] > requiredReports[requiredIndex])
{
missingReports.Add(requiredReports[requiredIndex]);
requiredIndex++;
continue;
}
}
for (var i = requiredIndex; i < requiredCount; i++ )
{
missingReports.Add(requiredReports[i]);
}
显然,为了代码的清晰性,您应该使用Linq。这是为了避免多次迭代列表,但这样做的成本对于清晰理解代码来说是值得的。