linq 任何VS都存在-有什么区别?

2eafrhcq  于 2023-09-28  发布在  其他
关注(0)|答案(6)|浏览(108)

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

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

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

更新1

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

更新2

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

yhxst69z

yhxst69z1#

参阅文档
List.Exists(对象方法- MSDN)
确定List(T)是否包含与指定 predicate 定义的条件匹配的元素。
这是从.NET 2.0开始的,所以在LINQ之前。本应与Predicatedelegate一起使用,但lambda表达式是向后兼容的。此外,只有List才有这个(甚至IList也没有)
IEnumerable.Any(扩展方法- MSDN)
确定序列的任何元素是否满足条件。
这在.NET 3.5中是新的,使用Func(TSource,bool)作为参数,因此它旨在与lambda表达式和LINQ一起使用。
在行为上,它们是相同的。

qzwqbdag

qzwqbdag2#

不同之处在于,Anyextension method,适用于在System.Linq.Enumerable上定义的任何IEnumerable<T>。它可以在任何IEnumerable<T>示例上使用。
Exists似乎不是extension method。我猜科尔的类型是List<T>。如果是这样的话,Exists是一个instance method,它的功能与Any非常相似。

    • 一个比另一个更普遍。
      *Any也有一个重载,它不带参数,只是在可查询对象中查找任何项。
      *Exists没有这样的重载。
6fe3ivhb

6fe3ivhb3#

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

            }

测试列表生成器:

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;
    }

10 M记录
“任何:00:00:00.3770377存在:00:00:00.2490249”
500万条记录
“任何:00:00:00.0940094评论者:00:00:00.1420142”
1 M记录
“任何:00:00:00.0180018存在:00:00:00.0090009”
对于500 k,(我还翻转了它们被评估的顺序,以查看是否没有与首先运行的操作相关联的额外操作。
“存在:00:00:00.0050005任意:00:00:00.0100010”
10万条记录
“存在:00:00:00.0010001任意:00:00:00.0020002”
看起来Any慢了2个数量级。

**编辑:**对于5 M和10 M的记录,我改变了它生成列表的方式,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"))
            {

            }
        }

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

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
“任何: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”

xoefb8l8

xoefb8l84#

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

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

首先:使用秒表进行基准测试并不精确(see series0ne's answer on a different, but similiar, topic),但它比DateTime精确得多。
获得真正精确读数的方法是使用性能分析。但是,了解这两个方法的性能如何相互衡量的一种方法是执行两个方法 * 加载 * 次,然后比较每个方法的最快执行时间。这样,JIT和其他噪声给我们带来的读数不好(确实如此)真的不重要,因为在某种意义上,这两种执行都是“同样误导”。

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;
    }

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

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

有一个微小的差异,但它太小了,不能用背景噪音来解释。我的猜测是,如果一个人做10 000或100 000 Exists()Any(),那么这个微小的差异或多或少会消失。

yrwegjxp

yrwegjxp5#

当您校正测量值时-如上所述:Any和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.
cigdeys3

cigdeys36#

此外,只有当Value的类型为bool时,这才有效。通常,这与 predicate 一起使用。任何 predicate 通常用来判断是否存在满足给定条件的元素.在这里,您只是将元素iMap到bool属性。它将搜索Value属性为true的“i”。一旦完成,该方法将返回true。

相关问题