根据另一个int列表填写缺失值

时间:2012-01-18 12:41:43

标签: c# asp.net .net linq lambda

我有一个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值的db条目填充此IEnumerable:

salesReports = _salesReport.GetAll(fromDate, toDate);

然后我有一个int列表,它们都是可用的ItemID:

var ItemIDList = new List<int>();

我的问题是我必须插入所有不在IEnumerable中的ItemID的SalesReport,因此对于ItemIDList的每个值,我检查IEnumerable中是否至少有一个相应的ItemID,如果不是,我有附加具有该ItemID的新SalesReport。

我怎样才能轻松完成这项工作?

2 个答案:

答案 0 :(得分:1)

您可以使用Range&amp; Except可以执行此操作。

var unusedIds = Enumerable.Range(1, _salesReport.select(sr => sr.ItemID).Max())
                .Except(_salesReport.select(sr => sr.ItemID));
ItemIDList.AddRange(unusedIds);

我不知道Except函数有多贵,猜测它会为Find中的_salesReport范围内的每个项目执行Except。我会查一查并回复你。

。 。 。当然我错了Jon Skeets Eudlinq Max()的实现只消耗每个序列一次,ILSpy向我展示了.Net源代码中的类似优化。

NB :调用_salesReport以获取整数范围 - 当然 - 会迭代_salesReport一次,所以总共迭代{{1}两次。

如果这太贵了,您可以从_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);

答案 1 :(得分:0)

作为练习,我试图以最有效的方式解决这个问题:

        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。这是为了避免多次迭代列表,但这样做的成本对于清楚理解代码的能力是值得的。

相关问题