Sorting arrays of objects

D

Dylan Parry

Hi,

I have an array of objects of the following class:

public class Appendix
{
private int id;
private int document;
private string title;
private string number;
private string text;
}

The 'id' represents the ID column in the database, the 'document' is the
ID of the parent object, the 'title' is a string representing the title
of the appendix, 'number' is a string (I'll explain that shortly)
representing the appendix number, and finally 'text' contains the text
of the appendix. All pretty self-explanatory, except for the number.

The 'number' property is a string because different documents number
their appendices in different ways. Some label them A-Z and others 1-99,
so the database was set up in such a way that it has a varchar column
for the number. This is mildly annoying, but can't be changed now.

This is all well and good until there are more than 9 appendices in a
document, and they are labelled numerically. When they come out of the
database they are in the order 1, 10, 11, 2, 3, ... etc.

What I want to do is sort the array of objects based on the 'number' but
sort them so that they come out as 1, 2, 3, ... , 10, 11, without
screwing up the sorting when they are ordered as A, B, C, ... etc.

Is there a way to do this? Presumably I'll have to implement IComparable
and write a CompareTo method, but I really have no idea where to begin
with the logic of how to compare strings to get the desired result!
 
A

Alberto Poblacion

Dylan Parry said:
Is there a way to do this? Presumably I'll have to implement IComparable
and write a CompareTo method, but I really have no idea where to begin
with the logic of how to compare strings to get the desired result!

Easy: Convert them to integers and then compare the integers:

public int CompareTo(object obj) {
if (obj is Appendix)
{
Appendix otherAppendix = (Appendix) obj;
int thisNumber = int.Parse(this.number);
int otherNumber = int.Parse(otherAppendix.number);
return thisNumber.CompareTo(otherNumber);
}
else
{
throw new ArgumentException("Object is not an Appendix");
}
}

Since you have some cases in which the appendices are numbered as "A"-"Z",
an additional refinement could consist of replacing the "int.Parse" with
"int.TryParse", and performing a string comparison when the TryParse fails.
 
D

Dylan Parry

Alberto said:
Easy: Convert them to integers and then compare the integers: ....
Since you have some cases in which the appendices are numbered as "A"-"Z",
an additional refinement could consist of replacing the "int.Parse" with
"int.TryParse", and performing a string comparison when the TryParse fails.

Of course! I didn't think of that, and it's such a simple solution. Any
idea what would happen if, God forbid, there's an appendix called 10A? :s
 
A

Alberto Poblacion

Dylan Parry said:
Of course! I didn't think of that, and it's such a simple solution. Any
idea what would happen if, God forbid, there's an appendix called 10A? :s

If you implement my suggestion of "TryParse", the TryParse would return
failure and you would then sort it alphabetically... which means that 10A
would come *before* 9A. If this is not what you want, you will need to think
about the possible combinations of numbers and letters that you allow in
"number", and decide on how each combination shoud be sorted (for instance:
if it starts with a number and then is followed by letters, sort numerically
on the number part and the alphabetically on the rest of the string). You
would need to specifically code for such criteria.
 
D

Dylan Parry

Alberto said:
If you implement my suggestion of "TryParse", the TryParse would return
failure and you would then sort it alphabetically... which means that 10A
would come *before* 9A. If this is not what you want, you will need to think
about the possible combinations of numbers and letters that you allow in
"number", and decide on how each combination shoud be sorted (for instance:
if it starts with a number and then is followed by letters, sort numerically
on the number part and the alphabetically on the rest of the string). You
would need to specifically code for such criteria.

Indeed, I tried it and that's exactly how it works. For the moment it's
fine for our purposes as this situation really hasn't come up and
potentially never will. I don't want to spend too much time working on a
solution to a problem that isn't likely to come up :)

Thanks for the original suggestion though - it works fantastically!
 
C

Chris Dunaway

Indeed, I tried it and that's exactly how it works. For the moment it's
fine for our purposes as this situation really hasn't come up and
potentially never will. I don't want to spend too much time working on a
solution to a problem that isn't likely to come up :)

Thanks for the original suggestion though - it works fantastically!

You could also pad the number on the left with zeroes internally to do
the sort, then it would come out correctly with just an alphabetic
sort:


public int CompareTo(object obj) {
if (obj is Appendix)
{
Appendix otherAppendix = (Appendix) obj;
return this.Number.PadLeft(8,'0').CompareTo
(otherAppendix.Number.PadLeft(8,'0'));
}
else
{
throw new ArgumentException("Object is not an Appendix");
}
}

This way if you had numbers like 1, 10, 2, 3, AB, 4F6, C3...etc.When
sorted they would be internally changed to

00000001, 00000010, 00000002, 00000003, 000000AB, 000004F6, 000000C3
and would sort to this order:

00000001
00000002
00000003
00000010
000000AB
000000C3
000004F6


Just a thought.

Chris
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top