.NET、.Contains() 和 .Count() 哪个更快?

发布于 2024-10-23 23:32:24 字数 853 浏览 2 评论 0原文

我想将修改记录的数组与从数据库中提取的记录列表进行比较,并从数据库中删除传入数组中不存在的那些记录。修改后的数组来自维护数据库的客户端应用程序,并且此代码在 WCF 服务应用程序中运行,因此如果客户端从数组中删除一条记录,则应从数据库中删除该记录。以下是示例代码片段:

public void UpdateRecords(Record[] recs)
{
    // look for deleted records
    foreach (Record rec in UnitOfWork.Records.ToList())
    {
        var copy = rec;
        if (!recs.Contains(rec))                      // use this one?
        if (0 == recs.Count(p => p.Id == copy.Id))    // or this one?
        {
            // if not in the new collection, remove from database
            Record deleted = UnitOfWork.Records.Single(p => p.Id == copy.Id);
            UnitOfWork.Remove(deleted);
        }
    }
    // rest of method code deleted
}

我的问题:使用 Count 方法相对于 Contains 方法是否有速度优势(或其他优势)? Id 属性保证是唯一的并标识该特定记录,因此您不需要进行按位比较,正如我假设 Contains 可能会做的那样。

有人吗? 谢谢,戴夫

I want to compare an array of modified records against a list of records pulled from the database, and delete those records from the database that do not exist in the incoming array. The modified array comes from a client app that maintains the database, and this code runs in a WCF service app, so if the client deletes a record from the array, that record should be deleted from the database. Here's the sample code snippet:

public void UpdateRecords(Record[] recs)
{
    // look for deleted records
    foreach (Record rec in UnitOfWork.Records.ToList())
    {
        var copy = rec;
        if (!recs.Contains(rec))                      // use this one?
        if (0 == recs.Count(p => p.Id == copy.Id))    // or this one?
        {
            // if not in the new collection, remove from database
            Record deleted = UnitOfWork.Records.Single(p => p.Id == copy.Id);
            UnitOfWork.Remove(deleted);
        }
    }
    // rest of method code deleted
}

My question: is there a speed advantage (or other advantage) to using the Count method over the Contains method? the Id property is guaranteed to be unique and to identify that particular record, so you don't need to do a bitwise compare, as I assume Contains might do.

Anyone?
Thanks, Dave

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

逆流 2024-10-30 23:32:24

这会更快:

if (!recs.Any(p => p.Id == copy.Id)) 

这与使用 Count() 具有相同的优点 - 但与 Count() 不同,它也会在找到第一个匹配项后停止 >

This would be faster:

if (!recs.Any(p => p.Id == copy.Id)) 

This has the same advantages as using Count() - but it also stops after it finds the first match unlike Count()

夜唯美灬不弃 2024-10-30 23:32:24

您甚至不应该考虑 Count,因为您只是检查记录是否存在。您应该使用 Any 来代替。

使用 Count 强制迭代整个枚举以获得正确的计数,Any 一旦找到第一个元素就停止枚举。

至于 Contains 的使用,您需要考虑指定类型的引用是否等同于您正在执行的 Id 比较。默认情况下不是这样。

You should not even consider Count since you are only checking for the existence of a record. You should use Any instead.

Using Count forces to iterate the entire enumerable to get the correct count, Any stops enumerating as soon as you found the first element.

As for the use of Contains you need to take in consideration if for the specified type reference equality is equivalent to the Id comparison you are performing. Which by default it is not.

笑饮青盏花 2024-10-30 23:32:24

假设 Record 正确实现了 GetHashCode 和 Equals,我会完全使用不同的方法:

// I'm assuming it's appropriate to pull down all the records from the database
// to start with, as you're already doing it.
foreach (Record recordToDelete in UnitOfWork.Records.ToList().Except(recs))
{
    UnitOfWork.Remove(recordToDelete);
}

基本上不需要进行 N * M 查找time - 上面的代码最终将根据其哈希码从 recs 构建一组记录,并且比原始代码更有效地查找不匹配项。

如果您实际上还有更多要做的事情,您可以使用:(

HashSet<Record> recordSet = new HashSet<Record>(recs);

foreach (Record recordFromDb in UnitOfWork.Records.ToList())
{
    if (!recordSet.Contains(recordFromDb))
    {
        UnitOfWork.Remove(recordFromDb);
    }
    else
    {
        // Do other stuff
    }
}

我不太确定为什么您的原始代码使用 Single 从数据库中重新获取记录,而您已经将其作为<代码>记录...)

Assuming Record implements both GetHashCode and Equals properly, I'd use a different approach altogether:

// I'm assuming it's appropriate to pull down all the records from the database
// to start with, as you're already doing it.
foreach (Record recordToDelete in UnitOfWork.Records.ToList().Except(recs))
{
    UnitOfWork.Remove(recordToDelete);
}

Basically there's no need to have an N * M lookup time - the above code will end up building a set of records from recs based on their hash code, and find non-matches rather more efficiently than the original code.

If you've actually got more to do, you could use:

HashSet<Record> recordSet = new HashSet<Record>(recs);

foreach (Record recordFromDb in UnitOfWork.Records.ToList())
{
    if (!recordSet.Contains(recordFromDb))
    {
        UnitOfWork.Remove(recordFromDb);
    }
    else
    {
        // Do other stuff
    }
}

(I'm not quite sure why your original code is refetching the record from the database using Single when you've already got it as rec...)

三生池水覆流年 2024-10-30 23:32:24

Contains() 将对您的对象使用 Equals() 。如果您没有重写此方法,Contains() 甚至可能返回不正确的结果。如果您已重写它以使用对象的 Id 来确定身份,那么在这种情况下,Count()Contains() 几乎执行以下操作完全相同的事情。除了 Contains() 一旦遇到匹配就会短路,而 Count() 会继续计数。 Any() 可能是比它们更好的选择。

您确定这是您应用程序的瓶颈吗?对我来说,这感觉像是过早的优化。这是万恶之源,你知道的:)

Contains() is going to use Equals() against your objects. If you have not overridden this method, it's even possible Contains() is returning incorrect results. If you have overridden it to use the object's Id to determine identity, then in that case Count() and Contains() are almost doing the exact same thing. Except Contains() will short circuit as soon as it hits a match, where as Count() will keep on counting. Any() might be a better choice than both of them.

Do you know for certain this is a bottleneck in your app? It feels like premature optimization to me. Which is the root of all evil, you know :)

风启觞 2024-10-30 23:32:24

由于可以保证有 1 个且只有 1 个,因此 Any 可能会更快。因为一旦它找到匹配的记录就会返回 true。

Count 将遍历整个列表,对每次出现的情况进行计数。因此,如果该项目在 1000 个项目列表中排名第一,它将检查这 1000 个项目中的每一个。

编辑

此外,这可能是一个值得提及的时候,不要进行过早的优化。

连接你的两种方法,在每个方法之前和之后放一个秒表。
创建一个足够大的列表(1000 个项目或更多,具体取决于您的域。)并查看哪个更快。

我的猜测是我们在这里谈论的是女士的顺序。

我完全支持编写高效的代码,只要确保您不会花费数小时来在每天调用两次的方法上节省 5 毫秒即可。

Since you're guarenteed that there will be 1 and only 1, Any might be faster. Because as soon as it finds a record that matches it will return true.

Count will traverse the entire list counting each occurrence. So if the item is #1 in the list of 1000 items, it's going to check each of the 1000.

EDIT

Also, this might be a time to mention not doing a premature optimization.

Wire up both your methods, put a stopwatch before and after each one.
Create a sufficiently large list (1000 items or more, depending on your domain.) And see which one is faster.

My guess is that we're talking on the order of ms here.

I'm all for writing efficient code, just make sure you're not taking hours to save 5 ms on a method that gets called twice a day.

别把无礼当个性 2024-10-30 23:32:24

事情会是这样:

UnitOfWork.Records.RemoveAll(r => !recs.Any(rec => rec.Id == r.Id));

It would be so:

UnitOfWork.Records.RemoveAll(r => !recs.Any(rec => rec.Id == r.Id));
国产ˉ祖宗 2024-10-30 23:32:24

我可以建议一种替代方法吗?我相信这种方法应该更快,因为即使在第一场比赛之后计数也会继续。

public void UpdateRecords(Record[] recs)
{
    // look for deleted records
    foreach (Record rec in UnitOfWork.Records.ToList())
    {
        var copy = rec;
        if (!recs.Any(x => x.Id == copy.Id)
        {
            // if not in the new collection, remove from database
            Record deleted = UnitOfWork.Records.Single(p => p.Id == copy.Id);
            UnitOfWork.Remove(deleted);
        }
    }
    // rest of method code deleted
}

这样你就一定会在第一场比赛中中断,而不是继续计数。

May I suggest an alternative approach that should be faster I believe since count would continue even after the first match.

public void UpdateRecords(Record[] recs)
{
    // look for deleted records
    foreach (Record rec in UnitOfWork.Records.ToList())
    {
        var copy = rec;
        if (!recs.Any(x => x.Id == copy.Id)
        {
            // if not in the new collection, remove from database
            Record deleted = UnitOfWork.Records.Single(p => p.Id == copy.Id);
            UnitOfWork.Remove(deleted);
        }
    }
    // rest of method code deleted
}

That way you are sure to break on the first match instead of continue to count.

明明#如月 2024-10-30 23:32:24

如果需要知道元素的实际数量,请使用 Count();这是唯一的方法。如果要检查是否存在匹配记录,请使用 Any() 或 Contains()。两者都比 Count() 快得多,并且执行效果大致相同,但 Contains 将对整个对象进行相等性检查,而 Any() 将根据对象计算 lambda 谓词。

If you need to know the actual number of elements, use Count(); it's the only way. If you are checking for the existence of a matching record, use Any() or Contains(). Both are MUCH faster than Count(), and both will perform about the same, but Contains will do an equality check on the entire object while Any() will evaluate a lambda predicate based on the object.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文