Extension methods in IEnumerable <T>: how does it work?
From my mentor: Prefer your own methods (implemented directly in the collection) over IEnumerable extension methods, because:
LINQ-to-Objects extension methods are implemented in IEnumerable, which in the worst case scenario (when the item you are looking for does not exist in the collection) you have to list through all the elements. If you have a Contains or There is a method implemented directly on the collection, it could use internal knowledge and, perhaps, just perform a hash table or some other quick operation.
I was very confused because I think Microsoft should already have implemented a hash table for IEnumerable Contains / Exists. A quick test with a list and IEnumerable shows no differences:
static void Main(string[] args)
{
Console.Write("input the number of elements: ");
int count = Convert.ToInt32(Console.ReadLine());
Console.Write("input the number of loops: ");
int loop = Convert.ToInt32(Console.ReadLine());
Random r = new Random();
Stopwatch sw = new Stopwatch();
for (int i = 0; i < loop; i++)
{
var list = CreateListOfInt(count);
sw.Start();
for (int j = 0; j < count; j++)
{
DoContains(list, r.Next());
}
sw.Stop();
}
Console.WriteLine("List<T> native method: Iterated {0} times on {1} elements, elapsed :{2}",loop,count,sw.Elapsed);
sw.Reset();
for (int i = 0; i < loop; i++)
{
var list = CreateListOfInt(count);
sw.Start();
for (int j = 0; j < count; j++)
{
DoContainsEnumerable(list, r.Next());
}
sw.Stop();
}
Console.WriteLine("IEnumerable<T> extension method: Iterated {0} times on {1} elements, elapsed :{2}", loop, count, sw.Elapsed);
sw.Reset();
for (int i = 0; i < loop; i++)
{
var list = CreateListOfInt2(count);
sw.Start();
for (int j = 0; j < count; j++)
{
//make sure that the element is not in the list
DoContains(list, r.Next(20000, 50000));
}
sw.Stop();
}
Console.WriteLine("List<T> native method: element does not exist:Iterated {0} times on {1} elements, elapsed :{2}", loop, count, sw.Elapsed);
sw.Reset();
for (int i = 0; i < loop; i++)
{
var list = CreateListOfInt2(count);
sw.Start();
for (int j = 0; j < count; j++)
{
//make sure that the element is not in the list
DoContainsEnumerable(list, r.Next(20000, 50000));
}
sw.Stop();
}
Console.WriteLine("IEnumerable<T> extension method: element does not exist: Iterated {0} times on {1} elements, elapsed :{2}", loop, count, sw.Elapsed);
Console.ReadKey();
}
static List<int> CreateListOfInt(int count)
{
Random r = new Random(1000);
List<int> numbers = new List<int>(count);
for (int i = 0; i < count; i++)
{
numbers.Add(r.Next());
}
return numbers;
}
static bool DoContains(List<int> list, int number)
{
return list.Contains(number);
}
static bool DoContainsEnumerable(IEnumerable<int> list, int number)
{
return list.Contains(number);
}
//define the scope of randomly created number, to make sure that lookup number will not in the List
static List<int> CreateListOfInt2(int count)
{
Random r = new Random(1000);
List<int> numbers = new List<int>(count);
for (int i = 0; i < count; i++)
{
numbers.Add(r.Next(0,10000));
}
return numbers;
}
}
: HashSet, :
sw.Reset();
for (int i = 0; i < loop; i++)
{
var list = CreateListOfInt2(count);
HashSet<int> hashtable = new HashSet<int>(list);
sw.Start();
for (int j = 0; j < count; j++)
{
//make sure that the element is not in the list
hashtable.Contains(r.Next(20000, 50000));
}
sw.Stop();
}
Console.WriteLine("IEnumerable<T> extension method: element does not exist: Iterated {0} times on {1} elements, elapsed :{2}", loop, count, sw.Elapsed);
, ?
- ? ? , ?
LINQ , .
, Count :
if (source is Array)
return source.Length;
if (source is ICollection)
return source.Count;
// else iterate through all the items and count them.
Contains :
if (source is ICollection)
return source.Contains(item);
// else iterate through the enumerable, and see if item exists
a HashSet<T> ICollection<T>, Contains.
, LINQ . , , , , LINQ .