Linq .Any VS.Exists - 有什么区别?

Ant*_*y D 396 c# linq collections

在集合上使用Linq,以下代码行之间有什么区别?

if(!coll.Any(i => i.Value))
Run Code Online (Sandbox Code Playgroud)

if(!coll.Exists(i => i.Value))
Run Code Online (Sandbox Code Playgroud)

更新1

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

更新2

任何人都知道为什么这个没有代码?

Mei*_*bur 402

见文档

List.Exists(对象方法 - MSDN)

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

这是自.NET 2.0以来存在的,所以在LINQ之前.意味着要与Predicate 委托一起使用,但lambda表达式是向后兼容的.另外,Just List有这个(甚至不是IList)

IEnumerable.Any(扩展方法 - MSDN)

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

这是.NET 3.5中的新增功能,并使用Func(TSource,bool)作为参数,因此这适用于lambda表达式和LINQ.

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

  • 我后来做了[另一个帖子中的帖子](http://stackoverflow.com/a/21436464/1336654),其中我列出了.NET 2`List <>`实例方法的所有Linq"等价物". (4认同)
  • 这里的一些答案说any()比exists()慢。但在现实世界的用例中,您通常可以将其与其他 Linq 方法结合使用,这将使其更快,例如 `myIEnum.Where(a =&gt; String.Equals(a.sex, "male")).Any(a =&gt; String .Equals(a.name, "Joe"))`. 你不能像这样将where() 与exists() 一起使用。 (4认同)

Jar*_*Par 193

区别在于Any是IEnumerable<T>System.Linq.Enumerable上任何已定义的扩展方法.它可以在任何IEnumerable<T>实例上使用.

存在似乎不是一种扩展方法.我的猜测是coll是类型的List<T>.如果是这样Exists是一个实例方法,其功能与Any非常相似.

简而言之,这些方法基本相同.一个比另一个更普遍.

  • 任何也有一个不带参数的重载,只是查找枚举中的任何项目.
  • 存在没有这种过载.

  • 好吧(+1).List <T> .Exists自.Net 2以来一直存在,但仅适用于通用列表.IEnumerable <T> .Any在.Net 3中被添加为适用于任何可枚举集合的扩展.还有像List <T> .Count这样的类似成员,它是一个属性,IEnumerable <T> .Count() - 一个方法. (12认同)

Mat*_*ius 49

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"))
            {

            }
Run Code Online (Sandbox Code Playgroud)

测试列表生成器:

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;
    }
Run Code Online (Sandbox Code Playgroud)

拥有10M记录

"任何:00:00:00.3770377存在:00:00:00.2490249"

有5M记录

"任何:00:00:00.0940094存在:00:00:00.1420142"

拥有1M记录

"任何:00:00:00.0180018存在:00:00:00.0090009"

使用500k,(我也按顺序翻转它们进行评估,以查看是否没有与先运行的任何操作相关联的额外操作.)

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

拥有100k记录

"存在:00:00:00.0010001任何:00:00:00.0020002"

Any的幅度似乎要慢2.

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

新的测试机制:

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"))
            {

            }
        }
Run Code Online (Sandbox Code Playgroud)

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"))
            {
            }
        }
    }
Run Code Online (Sandbox Code Playgroud)

10M

"任何:00:00:00.1640164存在:00:00:00.0750075"

5M

"任何:00:00:00.0810081存在:00:00:00.0360036"

1M

"任何:00:00:00.0190019存在:00:00:00.0070007"

500K

"任何:00:00:00.0120012存在:00:00:00.0040004"

在此输入图像描述

  • 没有诋毁你,但我对这些基准感到怀疑。看看数字:每个结果都会发生递归(3770377:2490249)。至少对我来说,这是一个肯定的迹象,有些事情是不正确的。我对这里的数学不是百分百确定,但我认为这种重复模式发生的几率是 999^999(或 999!也许?)每个值中的 1。所以它连续发生 **8 次**的可能性是无穷小的。我认为这是因为您使用 [DateTime 进行基准测试](http://stackoverflow.com/questions/28637/is-datetime-now-the-best-way-to-measure-a-functions-performance)。 (4认同)
  • @JerriKangasniemi 我可以建议您修复它并发布答案吗 (2认同)

Jer*_*emi 14

作为Matas关于基准测试的答案的延续.

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

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

获得真正精确读数的方法是使用性能分析.但是,了解两种方法的性能如何相互衡量的一种方法是通过执行两种方法加载次数,然后比较每种方法的最快执行时间.这样,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;
    }
Run Code Online (Sandbox Code Playgroud)

在执行上述代码4次(其反过来执行1000次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
Run Code Online (Sandbox Code Playgroud)

这里一个细微的差别,但它太小,不被背景噪音来解释差异.我的猜测是,如果一个人会做10 000或10万Exists(),Any()相反,那个微小的差异会或多或少地消失.

  • 如果您发布的代码是您实际执行的代码,那么您获得类似结果就不足为奇了,因为您在两次测量中都调用了Exists.;) (9认同)
  • 最小值是因为我想比较每种方法的最快执行次数(=可能最小的背景噪声量).我可能会做更多的迭代,虽然它会更晚(我怀疑我的老板想要支付我这样做,而不是通过我们的积压工作) (2认同)
  • `Random r = new Random();` *确实*需要从 `for` 循环中取出。 (2认同)

小智 6

当您更正测量值时 - 如上所述: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.
Run Code Online (Sandbox Code Playgroud)


flq*_*flq 5

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