微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

C# foreach 循环和匹配有没有更快的方法来做到这一点?

如何解决C# foreach 循环和匹配有没有更快的方法来做到这一点?

我需要将一个列表中的值匹配到另一个列表。
两者都是列表。两者都有数十万条记录。
希望有人能告诉我一种方法来使这个更快一点,因为它需要很长时间才能匹配。

foreach (var item in availabilityItems)
{
    foreach (var page in from page in pricePagelist
        where item.Number == page.vendorItemNo
        where item.StartDate == page.SubSeasonStartDate
        where item.EndDate == page.SubSeasonEndDate
        select page)
    {
        item.vendorItemNo = page.vendorItemNo;
        item.PricePageNo = page.PricePageNo;
        item.NaItemNo = page.ItemNo;
    }
}

解决方法

如果它可以全部放入内存,您可以使用 Dictionary 来存储项目以便快速查找。根据您的数据库,这将减少您的数据库负载,消除对数据库端的索引和排序的需要,尤其是在您必须频繁运行此过程的情况下。

代码可能更容易理解,虽然阅读两个排序列表的另一个答案很聪明,但它可能需要更复杂的代码,并且还强制数据库执行 order by,使用索引和额外的 IO。

显然,如果您有超过 1000 万条记录,这会开始崩溃,但在该记录范围内应该没问题。

Dictionary<string,PageItem> lookup = new Dictionary<string,PageItem>(StringComparer.OrdinalIgnoreCase);

批量加载示例

foreach (var item in pricePageList)
{
    lookup[item.VendorItemNo + "|" + item.SubSeasonStartDate + "|" + item.SubSeasonEndDate] = item;
}

示例搜索:

foreach (var item in availabilityItems)
{
    string key = item.Number + "|" + item.SubSeasonStartDate + "|" + item.SubSeasonEndDate;
    if (lookup.TryGetValue(key,out PageItem match))
    {
        item.Number = match.VendorItemNo;
        item.PricePageNo = match.PricePageNo;
        item.NaItemNo = match.ItemNo;
    }
}
,

这是一种防止多次列表扫描的简单算法。

如果两个列表都在 Number/VendorItemNo 上排序,您可以使用 2 个索引变量自上而下扫描并将 NumberVendorItemNo 进行比较。如果 left 较大,则增加 right 的索引。否则,如果 right 更高,则增加左侧的索引。如果它们相等,则您匹配并增加两个索引。这背后的整个想法是您只需一次浏览每个列表。它也可以用于多个列表。

例如两个按 id 排序的列表。

使用索引扫描它们:

1234 <-    1233 <-
1236       1234
1237       1235
1238       1238

比较一下,左边比右边高,右边增加。


1234 <-    1233
1236       1234 <-
1237       1235
1238       1238

我们有一场比赛。 (当然你有一些额外的标准需要检查......)同时增加


1234       1233
1236 <-    1234
1237       1235 <-
1238       1238

左边高,右边增加


1234       1233
1236 <-    1234
1237       1235
1238       1238 <-

现在右边更高,所以向左增加


1234       1233
1236       1234
1237 <-    1235
1238       1238 <-

右边还高,再增加左边。


1234       1233
1236       1234
1237       1235
1238 <-    1238 <-

我们匹配了...所以只有 1234 和 1238 匹配。

如果一个超过列表的数量,你就完成了。

,

假设 pricePageList 包含关于三个字段组合的唯一元素,您可以构造一个包含页面的 Dictionary<TKey,Page>,使用 ValueTuple<int,DateTime,DateTime> 作为键。这种类型是开箱即用的,因此您不必提供自定义 IEqualityComparer<TKey>

var pricePageDictionary = pricePageList
    .ToDictionary(p => (p.VendorItemNo,p.SubSeasonStartDate,p.SubSeasonEndDate));

foreach (var item in availabilityItems)
{
    var key = (item.Number,item.StartDate,item.EndDate);
    if (pricePageDictionary.TryGetValue(key,out var page))
    {
        item.VendorItemNo = page.VendorItemNo;
        item.PricePageNo = page.PricePageNo;
        item.NaItemNo = page.ItemNo;
    }
}

与嵌套循环方法相比,这应该非常快,因为在 Dictionary<TKey,TValue> 中搜索是一个 O(1) 操作。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。