C# LINQ .Any VS .Exists - 有什么区别?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/879391/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-05 05:11:12  来源:igfitidea点击:

LINQ .Any VS .Exists - What's the difference?

c#linqcollections

提问by Anthony D

Using LINQ on collections, what is the difference between the following lines of code?

在集合上使用 LINQ,以下几行代码有什么区别?

if(!coll.Any(i => i.Value))

and

if(!coll.Exists(i => i.Value))

Update 1

更新 1

When I disassemble .Existsit looks like there is no code.

当我反汇编时,.Exists它看起来没有代码。

Update 2

更新 2

Anyone know why there is no code there for this one?

有谁知道为什么没有这个代码?

采纳答案by Meinersbur

See documentation

查看文档

List.Exists(Object method - MSDN)

List.Exists(对象方法 - MSDN)

Determines whether the List(T) contains elements that match the conditions defined by the specified predicate.

确定 List(T) 是否包含与指定谓词定义的条件匹配的元素。

This exists since .NET 2.0, so before LINQ. Meant to be used with the Predicate delegate, but lambda expressions are backward compatible. Also, just List has this (not even IList)

这从 .NET 2.0 开始就存在,所以在 LINQ 之前。旨在与 Predicate delegate一起使用,但 lambda 表达式向后兼容。另外,只有 List 有这个(甚至 IList 都没有)

IEnumerable.Any(Extension method - MSDN)

IEnumerable.Any(扩展方法 - MSDN)

Determines whether any element of a sequence satisfies a condition.

确定序列的任何元素是否满足条件。

This is new in .NET 3.5 and uses Func(TSource, bool) as argument, so this was intended to be used with lambda expressions and LINQ.

这是 .NET 3.5 中的新功能,并使用 Func(TSource, bool) 作为参数,因此它旨在与 lambda 表达式和 LINQ 一起使用。

In behaviour, these are identical.

在行为上,这些是相同的。

回答by JaredPar

The difference is that Any is an extension method for any IEnumerable<T>defined on System.Linq.Enumerable. It can be used on any IEnumerable<T>instance.

不同之处在于 Any 是IEnumerable<T>System.Linq.Enumerable 上定义的 any 的扩展方法。它可以用于任何IEnumerable<T>实例。

Exists does not appear to be an extension method. My guess is that coll is of type List<T>. If so Exists is an instance method which functions very similar to Any.

Exists 似乎不是扩展方法。我的猜测是 coll 是类型List<T>。If so Exists 是一个实例方法,其功能与 Any 非常相似。

In short, the methods are essentially the same. One is more general than the other.

总之方法基本相同。一种比另一种更通用。

  • Anyalso has an overload which takes no parameters and simply looks for any item in the enumerable.
  • Existshas no such overload.
  • Any也有一个不带参数的重载,只是在可枚举中查找任何项目。
  • Exists没有这样的过载。

回答by flq

Additionally, this will only work if Value is of type bool. Normally this is used with predicates. Any predicate would be generally used find whether there is any element satisfying a given condition. Here you're just doing a map from your element i to a bool property. It will search for an "i" whose Value property is true. Once done, the method will return true.

此外,这仅在 Value 为 bool 类型时才有效。通常这与谓词一起使用。任何谓词通常用于查找是否存在满足给定条件的任何元素。在这里,您只是将元素 i 映射到 bool 属性。它将搜索 Value 属性为 true 的“i”。完成后,该方法将返回 true。

回答by Matas Vaitkevicius

TLDR;Performance-wise Anyseems to be slower(if I have set this up properly to evaluate both values at almost same time)

TLDR;性能方面Any似乎较慢(如果我已正确设置以几乎同时评估两个值)

        var list1 = Generate(1000000);
        var forceListEval = list1.SingleOrDefault(o => o == "0123456789012");
        if (forceListEval != "sdsdf")
        {
            var s = string.Empty;
            var start2 = DateTime.Now;
            if (!list1.Exists(o => o == "0123456789012"))
            {
                var end2 = DateTime.Now;
                s += " Exists: " + end2.Subtract(start2);
            }

            var start1 = DateTime.Now;
            if (!list1.Any(o => o == "0123456789012"))
            {
                var end1 = DateTime.Now;
                s +=" Any: " +end1.Subtract(start1);
            }

            if (!s.Contains("sdfsd"))
            {

            }

testing list generator:

测试列表生成器:

private List<string> Generate(int count)
    {
        var list = new List<string>();
        for (int i = 0; i < count; i++)
        {
            list.Add( new string(
            Enumerable.Repeat("ABCDEFGHIJKLMNOPQRSTUVWXYZ", 13)
                .Select(s =>
                {
                    var cryptoResult = new byte[4];
                    new RNGCryptoServiceProvider().GetBytes(cryptoResult);
                    return s[new Random(BitConverter.ToInt32(cryptoResult, 0)).Next(s.Length)];
                })
                .ToArray())); 
        }

        return list;
    }

With 10M records

有 1000 万条记录

" Any: 00:00:00.3770377 Exists: 00:00:00.2490249"

“任何:00:00:00.3770377 存在:00:00:00.2490249”

With 5M records

有 500 万条记录

" Any: 00:00:00.0940094 Exists: 00:00:00.1420142"

“任何:00:00:00.0940094 存在:00:00:00.1420142”

With 1M records

有 100 万条记录

" Any: 00:00:00.0180018 Exists: 00:00:00.0090009"

“任何:00:00:00.0180018 存在:00:00:00.0090009”

With 500k, (I also flipped around order in which they get evaluated to see if there is no additional operation associated with whichever runs first.)

使用 500k,(我还翻转了对它们进行评估的顺序,以查看是否没有与先运行的操作相关联的其他操作。)

" Exists: 00:00:00.0050005 Any: 00:00:00.0100010"

" 存在:00:00:00.0050005 任何:00:00:00.0100010"

With 100k records

有 10 万条记录

" Exists: 00:00:00.0010001 Any: 00:00:00.0020002"

“ 存在:00:00:00.0010001 任何:00:00:00.0020002”

It would seem Anyto be slower by magnitude of 2.

它似乎Any慢了 2 级。

Edit:For 5 and 10M records I changed the way it generates the list and Existssuddenly became slower than Anywhich implies there's something wrong in the way I am testing.

编辑:对于 5 和 10M 记录,我改变了它生成列表的方式,Exists突然变得比Any这更慢,这意味着我测试的方式有问题。

New testing mechanism:

新的测试机制:

private static IEnumerable<string> Generate(int count)
    {
        var cripto = new RNGCryptoServiceProvider();
        Func<string> getString = () => new string(
            Enumerable.Repeat("ABCDEFGHIJKLMNOPQRSTUVWXYZ", 13)
                .Select(s =>
                {
                    var cryptoResult = new byte[4];
                    cripto.GetBytes(cryptoResult);
                    return s[new Random(BitConverter.ToInt32(cryptoResult, 0)).Next(s.Length)];
                })
                .ToArray());

        var list = new ConcurrentBag<string>();
        var x = Parallel.For(0, count, o => list.Add(getString()));
        return list;
    }

    private static void Test()
    {
        var list = Generate(10000000);
        var list1 = list.ToList();
        var forceListEval = list1.SingleOrDefault(o => o == "0123456789012");
        if (forceListEval != "sdsdf")
        {
            var s = string.Empty;

            var start1 = DateTime.Now;
            if (!list1.Any(o => o == "0123456789012"))
            {
                var end1 = DateTime.Now;
                s += " Any: " + end1.Subtract(start1);
            }

            var start2 = DateTime.Now;
            if (!list1.Exists(o => o == "0123456789012"))
            {
                var end2 = DateTime.Now;
                s += " Exists: " + end2.Subtract(start2);
            }

            if (!s.Contains("sdfsd"))
            {

            }
        }

Edit2:Ok so to eliminate any influence from generating test data I wrote it all to file and now read it from there.

Edit2:好的,为了消除生成测试数据的任何影响,我将其全部写入文件,现在从那里读取。

 private static void Test()
    {
        var list1 = File.ReadAllLines("test.txt").Take(500000).ToList();
        var forceListEval = list1.SingleOrDefault(o => o == "0123456789012");
        if (forceListEval != "sdsdf")
        {
            var s = string.Empty;
            var start1 = DateTime.Now;
            if (!list1.Any(o => o == "0123456789012"))
            {
                var end1 = DateTime.Now;
                s += " Any: " + end1.Subtract(start1);
            }

            var start2 = DateTime.Now;
            if (!list1.Exists(o => o == "0123456789012"))
            {
                var end2 = DateTime.Now;
                s += " Exists: " + end2.Subtract(start2);
            }

            if (!s.Contains("sdfsd"))
            {
            }
        }
    }

10M

10M

" Any: 00:00:00.1640164 Exists: 00:00:00.0750075"

“任何:00:00:00.1640164 存在:00:00:00.0750075”

5M

5M

" Any: 00:00:00.0810081 Exists: 00:00:00.0360036"

“任何:00:00:00.0810081 存在:00:00:00.0360036”

1M

1M

" Any: 00:00:00.0190019 Exists: 00:00:00.0070007"

“任何:00:00:00.0190019 存在:00:00:00.0070007”

500k

50万

" Any: 00:00:00.0120012 Exists: 00:00:00.0040004"

“任何:00:00:00.0120012 存在:00:00:00.0040004”

enter image description here

在此处输入图片说明

回答by Jerri Kangasniemi

As a continuation on Matas' answeron benchmarking.

作为Matas对基准测试的回答的延续。

TL/DR: Exists() and Any() are equally fast.

TL/DR:Exists() 和 Any() 同样快。

First off: Benchmarking using Stopwatch is not precise (see series0ne's answer on a different, but similiar, topic), but it is far more precise than DateTime.

首先:使用秒表进行基准测试并不精确(请参阅 series0ne 对不同但相似的主题的回答),但它比 DateTime 精确得多。

The way to get really precise readings is by using Performance Profiling. But one way to get a sense of how the two methods' performance measure up to each other is by executing both methods loadsof times and then comparing the fastest execution time of each. That way, it really doesn't matter that JITing and other noise gives us bad readings (and it does), because both executions are "equally misguiding" in a sense.

获得真正精确读数的方法是使用性能分析。但有办法通过执行这两种方法得到的两种方法的性能如何测量到对方是感负载的时间,然后比较各最快执行时间。这样,JITing 和其他噪音给我们带来糟糕的读数(确实如此并不重要,因为在某种意义上,这两种执行都“同样具有误导性”。

static void Main(string[] args)
    {
        Console.WriteLine("Generating list...");
        List<string> list = GenerateTestList(1000000);
        var s = string.Empty;

        Stopwatch sw;
        Stopwatch sw2;
        List<long> existsTimes = new List<long>();
        List<long> anyTimes = new List<long>();

        Console.WriteLine("Executing...");
        for (int j = 0; j < 1000; j++)
        {
            sw = Stopwatch.StartNew();
            if (!list.Exists(o => o == "0123456789012"))
            {
                sw.Stop();
                existsTimes.Add(sw.ElapsedTicks);
            }
        }

        for (int j = 0; j < 1000; j++)
        {
            sw2 = Stopwatch.StartNew();
            if (!list.Exists(o => o == "0123456789012"))
            {
                sw2.Stop();
                anyTimes.Add(sw2.ElapsedTicks);
            }
        }

        long existsFastest = existsTimes.Min();
        long anyFastest = anyTimes.Min();

        Console.WriteLine(string.Format("Fastest Exists() execution: {0} ticks\nFastest Any() execution: {1} ticks", existsFastest.ToString(), anyFastest.ToString()));
        Console.WriteLine("Benchmark finished. Press any key.");
        Console.ReadKey();
    }

    public static List<string> GenerateTestList(int count)
    {
        var list = new List<string>();
        for (int i = 0; i < count; i++)
        {
            Random r = new Random();
            int it = r.Next(0, 100);
            list.Add(new string('s', it));
        }
        return list;
    }

After executing the above code 4 times (which in turn do 1 000 Exists()and Any()on a list with 1 000 000 elements), it's not hard to see that the methods are pretty much equally fast.

执行上述代码 4 次(依次执行 1 000 次Exists()Any()在具有 1 000 000 个元素的列表上)后,不难看出这些方法的速度几乎一样快。

Fastest Exists() execution: 57881 ticks
Fastest Any() execution: 58272 ticks

Fastest Exists() execution: 58133 ticks
Fastest Any() execution: 58063 ticks

Fastest Exists() execution: 58482 ticks
Fastest Any() execution: 58982 ticks

Fastest Exists() execution: 57121 ticks
Fastest Any() execution: 57317 ticks

There isa slight difference, but it's too small a difference to not be explained by background noise. My guess would be that if one would do 10 000 or 100 000 Exists()and Any()instead, that slight difference would disappear more or less.

这里一个细微的差别,但它是不是背景噪音来解释过小的差异。我的猜测是,如果人们做 10 000 或 100 000 次Exists()Any()相反,这种细微的差异或多或少会消失。

回答by jasmintmp

When you correct the measurements - as mentioned above: Any and Exists, and adding average - we'll get following output:

当您更正测量值时 - 如上所述:Any and Exists,并添加平均值 - 我们将得到以下输出:

Executing search Exists() 1000 times ... 
Average Exists(): 35566,023
Fastest Exists() execution: 32226 

Executing search Any() 1000 times ... 
Average Any(): 58852,435
Fastest Any() execution: 52269 ticks

Benchmark finished. Press any key.