根据另一个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。

我怎样才能轻松做到这一点?

根据另一个int列表填充缺少的值

您可以使用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。这是为了避免多次迭代列表,但这样做的成本对于清晰理解代码来说是值得的。