为了账号安全,请及时绑定邮箱和手机立即绑定

如何使用IEqualityComparer加快许多字段的比较?

如何使用IEqualityComparer加快许多字段的比较?

C#
阿晨1998 2022-08-20 16:06:08
我在数据库中有一个项目列表,我用以下方式检索它:AE_AlignedPartnersList<AE_AlignedPartners> ae_alignedPartners_olds = ctx.AE_AlignedPartners.AsNoTracking().ToList();比,我得到并序列化了一个使用JSON的新列表(具有相同的对象类型):List<AE_AlignedPartners> ae_alignedPartners_news = GetJSONPartnersList();比我得到两者的交集:var IDSIntersections = (from itemNew in ae_alignedPartners_news                        join itemOld in ae_alignedPartners_olds on itemNew.ObjectID equals itemOld.ObjectID                        select itemNew).Select(p => p.ObjectID).ToList();现在,由于这些交集,我需要检查某些记录是否已更改,检查许多字段,然后添加到更新的“监视”列表中。代码如下:IList<AE_AlignedPartners> ae_alignedPartners_toUpdate = new List<AE_AlignedPartners>();foreach (var item in IDSIntersections){    var itemOld = ae_alignedPartners_olds.First(p => p.ObjectID == item);    var itemNew = ae_alignedPartners_news.First(p => p.ObjectID == item);    if (itemOld.Field1 != itemNew.Field1 ||        itemOld.Field2 != itemNew.Field2 ||        itemOld.Field3 != itemNew.Field3 ||        itemOld.Field4 != itemNew.Field4 ||        itemOld.Field5 != itemNew.Field5 ||        itemOld.Field6 != itemNew.Field6 ||        itemOld.Field7 != itemNew.Field7 ||        itemOld.Field8 != itemNew.Field8 ||        itemOld.Field9 != itemNew.Field9)    {        AE_AlignedPartners toUpdate = mapper.Map<AE_AlignedPartners, AE_AlignedPartners>(itemNew);        toUpdate.ID = itemOld.ID;        ae_alignedPartners_toUpdate.Add(toUpdate);    }}这是非常慢的(发布约4分钟,约70k条记录)。最近我在这里发现了,它确实加快了比较的进程。IEqualityComparer在这种情况下,我可以利用它吗?或者哪些是有效的优化?我不会使用建议的,因为这将意味着现在需要大量的重构(我将在下一个项目中这样做,承诺)。FullOuterJoin有什么提示吗?谢谢
查看完整描述

2 回答

?
千万里不及你

TA贡献1784条经验 获得超9个赞

您有嵌套循环实现


// O(N) : Loop over IDSIntersections

foreach (var item in IDSIntersections)

{

    // O(N) : Again, loop over ae_alignedPartners_olds

    var itemOld = ae_alignedPartners_olds.First(p => p.ObjectID == item);

    var itemNew = ae_alignedPartners_news.First(p => p.ObjectID == item);

    ...

在最坏的情况下,您将具有时间复杂性;数十亿个循环: .让我们借助字典摆脱内部循环:O(N) * O(N) = O(N**2)70k * 70k ~ 5e9


// O(N)

var dictOld = ae_alignedPartners_olds

  .GroupBy(p => p.ObjectID) // ObjectID should be a int, string or provide good GetHashCode()

  .ToDictionary(chunk => chunk.Key,

                chunk => chunk.First());


// O(N)

var dictNew = ae_alignedPartners_news

  .GroupBy(p => p.ObjectID) 

  .ToDictionary(chunk => chunk.Key,

                chunk => chunk.First());


// O(N)

foreach (var item in IDSIntersections)

{

   // O(1) : no loops when finding value by key in dictionary

   var itemOld = dictOld[item];      

   var itemNew = dictNew[item];

   ... 

现在我们将有关于循环:3 * O(N)3 * 70k ~ 2e5


查看完整回答
反对 回复 2022-08-20
?
慕哥9229398

TA贡献1877条经验 获得超6个赞

自定义会很好,但不是因为它提高了性能,它需要做同样的比较。但是因为在那里封装逻辑使其更易于维护,可读和可重用。您可以将其用于许多 LINQ 方法。IEqualityComparer<AE_AlignedPartners>


缓慢的是,您总是在 -循环中搜索旧项和新项。ObjectIdforeach


您不需要选择两者的共同点,如果您已经加入了旧的和新的,只需将整个实例存储在匿名类型中:ObjectID


var intersections = from itemNew in ae_alignedPartners_news

                    join itemOld in ae_alignedPartners_olds on itemNew.ObjectID equals itemOld.ObjectID

                    select new { New = itemNew, Old = itemOld };


foreach(var x in intersections)

{

    var itemOld = x.Old;

    var itemNew = x.New;

    // ... 

}


查看完整回答
反对 回复 2022-08-20
  • 2 回答
  • 0 关注
  • 117 浏览

添加回答

举报

0/150
提交
取消
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号