Tom said:
Just think for a moment what the code would look like if the requirement
were to sort on three, or four, or more property values. What I'm showing is
a generalized solution to the specific problem that the OP posed, that can
be used not only for this simple requirement but also for more complex
sorting requirements. Once you understand how to structure a sorting
solution this way, for the simple case given, you can easily apply it to
other and perhaps more complex problems. This is a good technique to add to
your toolkit - it's is simple and easy to remember, and scales easily as you
sort on more and more properties.
I created the following code to test this. The simple class that is
being sorted consists of 3 integers and 3 strings, randomly generated.
I did not implement IComparable on the class itself, but rather created
2 IComparer<SimpleClass> classes so I could keep them separate. I also
used a generic List since it was faster to create. For the comparer
that implements your method I padded all integers on the left with 0
for a total length of 5 and for the strings, I padded on the left with
the letter A to 9 characters. The strings were randomly generated with
a length from 4 to 9 characters.
For 100000 object, my method took .428 seconds. The method using
strings took 15.353 seconds. I don't know if this is conclusive, there
may be a problem with my testing methodolgy, but I would appreciate
some input. Here is the code: (I also used C# since I am faster at
developing with it)
Here are the comparer classes:
class Comparer1 : IComparer<SimpleClass>
{
public int Compare(SimpleClass x, SimpleClass y)
{
int result;
if (x.Prop1 == y.Prop1)
if (x.Prop2 == y.Prop2)
if (x.Prop3 == y.Prop3)
if (x.Prop4 == y.Prop4)
if (x.Prop5 == y.Prop5)
result = x.Prop6.CompareTo(y.Prop6);
else
result = x.Prop5.CompareTo(y.Prop5);
else
result = x.Prop4.CompareTo(y.Prop4);
else
result = x.Prop3.CompareTo(y.Prop3);
else
result = x.Prop2.CompareTo(y.Prop2);
else
result = x.Prop1.CompareTo(y.Prop1);
return result;
}
}
class Comparer2 : IComparer<SimpleClass>
{
public int Compare(SimpleClass x, SimpleClass y)
{
string str1 = x.Prop1.ToString().PadLeft(5, '0') +
x.Prop2.PadLeft(9, 'A') +
x.Prop3.ToString().PadLeft(5, '0') +
x.Prop4.ToString().PadLeft(5, '0') +
x.Prop5.PadLeft(9, 'A') +
x.Prop6.PadLeft(9, 'A');
string str2 = y.Prop1.ToString().PadLeft(5, '0') +
y.Prop2.PadLeft(9, 'A') +
y.Prop3.ToString().PadLeft(5, '0') +
y.Prop4.ToString().PadLeft(5, '0') +
y.Prop5.PadLeft(9, 'A') +
y.Prop6.PadLeft(9, 'A');
return str1.CompareTo(str2);
}
}
Here is the code to generate the objects, and sort them:
Random rnd = new Random(Environment.TickCount);
private const int instanceCount = 100000;
private void button3_Click(object sender, EventArgs e)
{
List<SimpleClass> items1 = createListOfItems();
List<SimpleClass> items2 = createListOfItems();
Stopwatch watch = new Stopwatch();
//Sort by Comparer1
watch.Reset();
watch.Start();
items1.Sort(new Comparer1());
watch.Stop();
MessageBox.Show(watch.Elapsed.ToString());
//Sort by Comparer2
watch.Reset();
watch.Start();
items2.Sort(new Comparer2());
watch.Stop();
MessageBox.Show(watch.Elapsed.ToString());
}
private List<SimpleClass> createListOfItems()
{
List<SimpleClass> list = new List<SimpleClass>();
for (int i = 0; i < instanceCount; i++)
{
SimpleClass s = new SimpleClass();
s.Prop1 = rnd.Next(1, 10001);
s.Prop2 = createRandomString(rnd.Next(4, 9));
s.Prop3 = rnd.Next(1, 10001);
s.Prop4 = rnd.Next(1, 10001);
s.Prop5 = createRandomString(rnd.Next(4, 9));
s.Prop6 = createRandomString(rnd.Next(4, 9));
list.Add(s);
}
return list;
}
private string createRandomString(int p)
{
string letters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
StringBuilder sb = new StringBuilder();
for (int i = 0; i < p; i++)
{
sb.Append(letters[rnd.Next(0, letters.Length)]);
}
return sb.ToString();
}