if(!coll.Any(i => i.Value))
并且
if(!coll.Exists(i => i.Value))
当我拆解
.Exists
时,看起来好像没有代码。为什么会这样呢?if(!coll.Any(i => i.Value))
并且
if(!coll.Exists(i => i.Value))
.Exists
时,看起来好像没有代码。为什么会这样呢?List.Exists(对象方法 - MSDN)
确定 List(T) 是否包含与指定谓词定义的条件匹配的元素。
这个方法自 .NET 2.0 就已经存在了,所以在 LINQ 之前。它的设计是用于 Predicate 委托,但是 lambda 表达式也是向后兼容的。而且,只有 List 类才有这个方法(甚至连 IList 都没有)。
IEnumerable.Any(扩展方法 - MSDN)
确定序列中是否有任何元素满足条件。
这是在.NET 3.5中新增的,它使用Func(TSource, bool)作为参数,因此旨在与lambda表达式和LINQ一起使用。
在行为方面,它们是相同的。
List<>
实例方法“相对应”的内容。 - Jeppe Stig NielsenmyIEnum.Where(a => String.Equals(a.sex, "male")).Any(a => String.Equals(a.name, "Joe"))
。你不能像这样在 exists() 中使用 where()。 - volkitAny
是System.Linq.Enumerable
中为任何IEnumerable<T>
定义的扩展方法。它可以用于任何IEnumerable<T>
实例。
Exists
似乎不是一个扩展方法。我猜测你的例子中col1
的类型是List<T>
。如果是这样,Exists
是一个实例方法,其功能与Any
非常相似。简而言之; 在性能方面,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;
}
有1000万条记录
"任何: 00:00:00.3770377 存在: 00:00:00.2490249"
有500万条记录
"任何: 00:00:00.0940094 存在: 00:00:00.1420142"
有100万条记录
"任何: 00:00:00.0180018 存在: 00:00:00.0090009"
有50万条记录,(我还改变了它们被评估的顺序,以查看是否与首先运行的任何一个相关的附加操作。)
"存在: 00:00:00.0050005 任何: 00:00:00.0100010"
有10万条记录
"存在: 00:00:00.0010001 任何: 00:00:00.0020002"
似乎Any
要慢大约两倍。
编辑:对于500万和1000万条记录,我改变了生成列表的方式,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"))
{
}
}
编辑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"))
{
}
}
}
10兆字节
"任意: 00:00:00.1640164 存在: 00:00:00.0750075"
5兆字节
"任意: 00:00:00.0810081 存在: 00:00:00.0360036"
1兆字节
"任意: 00:00:00.0190019 存在: 00:00:00.0070007"
500千字节
"任意: 00:00:00.0120012 存在: 00:00:00.0040004"
延续Matas的答案,对基准测试进行探讨。
简而言之:Exists()和Any()的速度相同。
首先:使用Stopwatch进行基准测试不是十分精确(请参见series0ne在另一个但类似主题上的回答),但它比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次后(每次对一个包含1,000,000个元素的列表执行1,000个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
存在一些微小的差异,但这种差异太小了,不能归因于背景噪声。我猜测如果进行10000或100000次 Exists()
和 Any()
,那么这种微小的差异将会更多或少消失。
Random r = new Random();
真的需要从那个 for
循环中拿出来。 - Jesse C. Slicer当你修正测量值 - 如上所述:任何和存在,并添加平均值 - 我们将得到以下输出:
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.
另外,这只适用于值为bool类型的情况。通常与谓词一起使用。任何谓词都可以用来判断是否有任何元素能满足给定条件。在此,您只需将元素 i 映射到一个布尔属性即可。它会搜索 Value 属性为 true 的“i”。完成后,该方法将返回 true。