Skip to content

Instantly share code, notes, and snippets.

@dbones
Created February 12, 2013 00:23
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dbones/4758935 to your computer and use it in GitHub Desktop.
Save dbones/4758935 to your computer and use it in GitHub Desktop.
List<T> vs HashSet<T> this is hack out code, it can be done better, but allows you to see how fast the collection will work with an object.
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Linq.Expressions;
namespace CollectionTest
{
class Program
{
static void Main(string[] args)
{
//this is hack out code, it can be done better,
//but allows you to see how fast the
//collection will work with an object.
//testing aginst a poco
var testRunner = new TestRunner<Person>();
testRunner.AddCollectionCtor(() => new List<Person>());
testRunner.AddCollectionCtor(() => new HashSet<Person>());
//testRunner.AddCollectionCtor(() => new LinkedList<Person>());
//testRunner.AddCollectionCtor(() => new SortedSet<Person>());
//testRunner.AddCollectionCtor(() => new Collection<Person>());
//testRunner.AddCollectionCtor(() => new ObservableCollection<Person>());
testRunner.AddDataBuilder(new PersonDataBuilder());
testRunner.AddTest(new InsertTest<Person>());
testRunner.AddTest(new ContainsTest<Person>());
testRunner.AddTest(new IterateOverTest<Person>());
testRunner.SetSampleSizes(1, 5, 10, 50, 100, 1000, 10000, 100000);
testRunner.Run();
Console.WriteLine("done");
Console.ReadLine();
//----------------------------
//test collection with strings
var testRunner2 = new TestRunner<string>();
testRunner2.AddCollectionCtor(() => new List<string>());
testRunner2.AddCollectionCtor(() => new HashSet<string>());
testRunner2.AddDataBuilder(new SimpleStringDataBuilder());
testRunner2.AddDataBuilder(new MediumStringDataBuilder());
testRunner2.AddDataBuilder(new LongStringDataBuilder());
testRunner2.AddTest(new InsertTest<string>());
testRunner2.AddTest(new ContainsTest<string>());
testRunner2.AddTest(new IterateOverTest<string>());
testRunner2.SetSampleSizes(1, 5, 10, 50, 100, 1000, 10000, 100000);
testRunner2.Run();
Console.WriteLine("done");
Console.ReadLine();
}
}
public class TestRunner<T>
{
private readonly List<ITest<T>> _tests = new List<ITest<T>>();
private readonly List<IDataBuilder<T>> _builders = new List<IDataBuilder<T>>();
private readonly List<int> _sampleSizes = new List<int>();
private readonly List<Expression<Func<ICollection<T>>>> _collectionCtors = new List<Expression<Func<ICollection<T>>>>();
public void AddCollectionCtor(Expression<Func<ICollection<T>>> ctor)
{
_collectionCtors.Add(ctor);
}
public void AddTest(ITest<T> test)
{
_tests.Add(test);
}
public void AddDataBuilder(IDataBuilder<T> dataBuilder)
{
_builders.Add(dataBuilder);
}
public void SetSampleSizes(params int[] sampleSizes)
{
_sampleSizes.AddRange(sampleSizes);
}
public void Run()
{
foreach (var test in _tests)
{
foreach (var dataBuilder in _builders)
{
foreach (var collectionCtorExp in _collectionCtors)
{
var collectionCtor = collectionCtorExp.Compile();
Console.WriteLine(string.Format("collection:" + collectionCtorExp));
foreach (var sampleSize in _sampleSizes)
{
List<double> times = new List<double>();
Run(collectionCtor, test, dataBuilder, sampleSize); //initalise
for (int i = 0; i < 5; i++)
{
GC.Collect(); //try to clean up for each test.
var timeSpan = Run(collectionCtor, test, dataBuilder, sampleSize);
times.Add(timeSpan.TotalMilliseconds);
}
var average = times.Average();
Console.WriteLine(string.Format("Test: {0}, Data: {1}, Sample Size: {2}, \t Time:{3}",
test, dataBuilder, sampleSize, average));
GC.Collect();
}
}
}
}
}
private TimeSpan Run(Func<ICollection<T>> collectionCtor, ITest<T> test, IDataBuilder<T> dataBuilder, int sampleSize)
{
test.SetDataBuilder(dataBuilder);
test.SetSampleSize(sampleSize);
test.Setup(collectionCtor);
Stopwatch sw = new Stopwatch();
sw.Start();
test.Run();
sw.Stop();
return sw.Elapsed;
}
}
#region tests
public interface ITest<T>
{
void SetSampleSize(int sampleSize);
void SetDataBuilder(IDataBuilder<T> dataBuilder);
void Setup(Func<ICollection<T>> collectionCtor);
void Run();
}
public abstract class Test<T> : ITest<T>
{
protected Func<ICollection<T>> _createCollection;
protected int _sampleSize;
protected Func<int, T> _createData;
protected ICollection<T> _collection;
public void SetSampleSize(int sampleSize)
{
_sampleSize = sampleSize;
}
public void SetDataBuilder(IDataBuilder<T> builder)
{
_createData = builder.Builder;
}
public abstract void Setup(Func<ICollection<T>> collectionCtor);
public abstract void Run();
public override string ToString()
{
return this.GetType().Name;
}
}
public class InsertTest<T> : Test<T>
{
public override void Setup(Func<ICollection<T>> collectionCtor)
{
_collection = collectionCtor();
}
public override void Run()
{
for (int i = 0; i < _sampleSize; i++)
{
_collection.Add(_createData(i));
}
}
}
public abstract class WithDataTest<T> : Test<T>
{
public override void Setup(Func<ICollection<T>> collectionCtor)
{
_collection = collectionCtor();
for (int i = 0; i < _sampleSize; i++)
{
_collection.Add(_createData(i));
}
}
}
public class IterateOverTest<T> : WithDataTest<T>
{
public override void Run()
{
foreach (var item in _collection)
{
var i = item;
}
}
}
public class ContainsTest<T> : WithDataTest<T>
{
public List<T> Items = new List<T>();
public override void Setup(Func<ICollection<T>> collectionCtor)
{
base.Setup(collectionCtor);
if (_collection.Count == 1)
{
Items = new List<T>() { _createData(0) };
}
if (_collection.Count == 2)
{
Items = new List<T>() { _createData(1) };
}
if (_collection.Count >= 3)
{
T last = _createData(_collection.Count - 1);
T middle = _createData(((_collection.Count() / 2) + 1));
Items = new List<T>() { _createData(1), last, middle };
}
}
public override void Run()
{
foreach (var index in Items)
{
var item = _collection.Contains(index);
}
}
}
#endregion
#region DataBuilders
public interface IDataBuilder<out T>
{
Func<int, T> Builder { get; }
}
public abstract class DataBuilderBase<T> : IDataBuilder<T>
{
public override string ToString()
{
return this.GetType().Name;
}
public abstract Func<int, T> Builder { get; }
}
#region Sample string and Person
class SimpleStringDataBuilder : DataBuilderBase<string>
{
public override Func<int, string> Builder
{
get { return i => string.Format("data {0}", i); }
}
}
class MediumStringDataBuilder : DataBuilderBase<string>
{
public override Func<int, string> Builder
{
get { return i => string.Format("data data data data data data data data data data {0}", i); }
}
}
class LongStringDataBuilder : DataBuilderBase<string>
{
public override Func<int, string> Builder
{
get { return i => string.Format("data data data data data data data data data data data data data data data data data data data data data data data data data data data data data data data data data data data data data data data data data data data data data data data data data data {0}", i); }
}
}
public class PersonDataBuilder : DataBuilderBase<Person>
{
public override Func<int, Person> Builder
{
get { return i => new Person(i); }
}
}
#endregion
#endregion
public class Person : IComparable<Person>
{
private readonly int _hash;
public Person(int i)
{
Name = string.Format("name {0}", i);
Age = i;
_hash = Name.GetHashCode() + Age.GetHashCode();
}
public string Name { get; private set; }
public int Age { get; private set; }
public override int GetHashCode()
{
return _hash;
}
public int CompareTo(Person other)
{
//return String.CompareOrdinal(Name, other.Name);
if (Age == other.Age)
{
return 0;
}
if (Age < other.Age)
{
return -1;
}
return +1;
}
public override bool Equals(object obj)
{
var person = obj as Person;
if (person == null) return false;
//return (Name.Equals(person.Name) && Age == person.Age); //very slow
//return (Age == person.Age && Name.Equals(person.Name)); //a little faster
return GetHashCode() == person.GetHashCode();
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment