假设这样的一个场景,有两个List<string>,分别是listA和listB,其中均有超过1w+的数据量,现在要求找出在B中但是不在A中的数据集合,
View Code
listB.ForEach(re =>
if (!listA.Contains(re))
//.......
这样写的话,是能够达到我们的需求的,但是很不幸,时间也会消耗很多。
我们看下List.Contains的源代码实现
View Code
[__DynamicallyInvokable]
public bool Contains(T item)
if (item == null)
for (int j = 0; j < this._size; j++)
if (this._items[j] == null)
return true;
return false;
EqualityComparer<T> comparer = EqualityComparer<T>.Default;
for (int i = 0; i < this._size; i++)
if (comparer.Equals(this._items[i], item))
return true;
return false;
这是因为List.Contains 本质是通过循环查找出该条数据,每一次的调用都会重头循环,所以效率很低。显然,这是不可取的。
于是,我们可以利用Hashtable的键值对改善这种情况。
代码如下:
View Code
listA.ForEach(re =>
table.Add(re, re);
listB.ForEach(re =>
if (table.ContainsKey(re))
//......
虽然,多了一个循环,但是总时间确实减少了很多。
我们可以看下Hashtable.ContainsKey源代码:
View Code
public virtual bool ContainsKey(object key)
uint num;
uint num2;
Hashtable.bucket bucket;
if (key == null)
throw new ArgumentNullException("key", Environment.GetResourceString("ArgumentNull_Key"));
Hashtable.bucket[] buckets = this.buckets;
uint num3 = this.InitHash(key, buckets.Length, out num, out num2);
int num4 = 0;
int index = (int) (num % buckets.Length);
bucket = buckets[index];
if (bucket.key == null)
return false;
if (((bucket.hash_coll & 0x7fffffff) == num3) && this.KeyEquals(bucket.key, key))
return true;
index = (int) ((index + num2) % ((ulong) buckets.Length));
while ((bucket.hash_coll < 0) && (++num4 < buckets.Length));
return false;
可见,哈希表的数据查找效率不是盖出来的。
我们可以通过下面的代码验证:
View Code
static void Main(string[] args)
List<string> listA = new List<string>();
List<string> listB = new List<string>();
for (int i = 0; i < 9999; i++)
listA.Add(i.ToString());
listB.Add((i + 1).ToString());
Stopwatch watch = new Stopwatch();
watch.Start();
listB.ForEach(re =>
if (!listA.Contains(re))
//.......
watch.Stop();
Console.WriteLine("List.Contains need {0}", watch.ElapsedTicks);
Hashtable table = new Hashtable();
watch.Restart();
listA.ForEach(re =>
table.Add(re, re);
listB.ForEach(re =>
if (table.ContainsKey(re))
//......
watch.Stop();
Console.WriteLine("Hashtable.Contains need {0}", watch.ElapsedTicks);
Console.ReadKey(true);
执行的结果如下:
List.Contains need 1920001 Hashtable.Contains need 8493 可以看到,效率提升了很多,当数据量越大,效果越明显。
注:本帖只是为了说明可以使用Hashtable改善List的查找性能,不做其他用处