在List泛型中查找一个值(唯一),究竟用哪种方法快点呢。for循环、foreach迭代器、Lambda表达式、Linq语句。
简单的写了一个程序测试一下。思路:构造一个有26843545个int元素List泛型(从小到大)。然后复制四份,准备用于查找。随机生成一个查找内容,用Stopwatch来检查运行时间。
代码如下:
1 static void Main(string[] args) 2 { 3 Stopwatch sw = new Stopwatch(); 4 Random rand=new Random(); 5 string output = "{0}运行使用了{1}毫秒"; 6 7 List<int> intlist = new List<int>(); 8 const int length = 26843545; 9 int temp; 10 11 for (int i = 0; i < length; i++) 12 { 13 intlist.Add(i); 14 } 15 16 int target = rand.Next(length); 17 18 Console.WriteLine("总长度{0},查找对象{1}", length, target); 19 20 List<int> forlist = new List<int>(); ; 21 forlist.Clear(); 22 forlist.AddRange(intlist); 23 24 List<int> lambdalist = new List<int>(); 25 lambdalist.Clear(); 26 lambdalist.AddRange(intlist); 27 28 List<int> foreachlist = new List<int>(); 29 foreachlist.Clear(); 30 foreachlist.AddRange(intlist); 31 32 List<int> linqlist = new List<int>(); 33 linqlist.Clear(); 34 linqlist.AddRange(intlist); 35 //------------------------------------ 36 // for 37 sw.Reset(); 38 sw.Start(); 39 for (int i = 0; i < length; i++) 40 { 41 if (forlist[i]==target) 42 { 43 temp = forlist[i]; 44 sw.Stop(); 45 Console.WriteLine(output, "for循环",sw.ElapsedMilliseconds); 46 } 47 } 48 //---------------------------------------------------------- 49 //foreach 50 sw.Reset(); 51 sw.Start(); 52 foreach (int item in foreachlist) 53 { 54 if (item == target) 55 { 56 temp = item; 57 sw.Stop(); 58 Console.WriteLine(output, "foreach循环", sw.ElapsedMilliseconds); 59 } 60 } 61 //------------------------------------------------ 62 //lambda 63 sw.Reset(); 64 sw.Start(); 65 temp= lambdalist.Where(x => x == target).First(); 66 sw.Stop(); 67 Console.WriteLine(output, "Lambda表达式", sw.ElapsedMilliseconds); 68 //---------------------------------------------------- 69 //Linq 70 sw.Reset(); 71 sw.Start(); 72 temp = (from y in linqlist 73 where y == target 74 select y).First(); 75 sw.Stop(); 76 Console.WriteLine(output, "Linq查询", sw.ElapsedMilliseconds); 77 //----------------------------------------------------------- 78 Console.Read(); 79 }
测试环境,core 2 duo P9400 2.4G双核,8G内存,win7 x64旗舰版。测试的结果,单位毫秒
| 查找对象 | for | foreach | Lambda | Linq |
| 25069205 | 242 | 286 | 296 | 294 |
| 5377884 | 52 | 62 | 70 | 63 |
| 11283402 | 110 | 129 | 140 | 134 |
| 5164132 | 52 | 59 | 66 | 59 |
| 23708079 | 239 | 274 | 518 | 514 |
| 26363083 | 271 | 308 | 576 | 568 |
| 1538372 | 15 | 17 | 23 | 18 |
| 7191108 | 70 | 84 | 91 | 85 |
| 3376391 | 33 | 39 | 46 | 39 |
| 9636456 | 91 | 171 | 119 | 113 |
| 23588001 | 233 | 276 | 385 | 289 |
简单的看出在百万个元素左右,差异并不十分大。总体性能for是最快,Lambda最低,但是Lambda和Linq基本差不多,性能比直接循环和迭代慢多了。
原因大致看了一下。在调用Where这个方法的时候,其实是用了很多层委托去调用,一直到调用Enumerable.CombinePredicates方法。
这个方法的实现代码
1 private static Func<TSource, bool> CombinePredicates<TSource>(Func<TSource, bool> predicate1, Func<TSource, bool> predicate2) 2 { 3 return delegate (TSource x) { 4 if (predicate1(x)) 5 { 6 return predicate2(x); 7 } 8 return false; 9 }; 10 } 11 12 13 14
可见,Linq的写法是提高程序员的编程效率,而执行效率是会降低的。但是在现在的硬件环境下,一般的数据容量这些降低可以忽略。但是如果你的数据量有1亿,就另当别论。不过,就我的这个程序,消耗内存也挺大的,一个控制台程序都要600多M内存(一共有5个千万单元的list喔^_^)。