Reputation: 704
I have a List<>
containing object from a class which has a String
property that I want to sort using the following rule:
X5
should be on top of the list.G2
will be after the X5
objects. H3
will be after the G2
objects.I tried some code but kept throwing this exception:
System.ArgumentException: Unable to sort because the IComparer.Compare() method returns inconsistent results. Either a value does not compare equal to itself, or one value repeatedly compared to another value yields different results. IComparer: ''.
Code attempt:
public class myObject: IComparable<myObject>
{
int id { get; set; }
string name { get; set; }
string code { get; set; }
public myObject()
{
}
public int CompareTo(myObject other)
{
//I don't know how to write the sort logic
}
}
Later I would like to create a list of "myObject" and sort it:
List<myObject> objects = new List<myObject>();
objects.Add(new MyObject() { id = 0, name = "JENNIFER"; code = "G2"; });
objects.Add(new MyObject() { id = 1, name = "TOM"; code = "H3"; });
objects.Add(new MyObject() { id = 2, name = "JACK"; code = "G2"; });
objects.Add(new MyObject() { id = 3, name = "SAM"; code = "X5"; });
objects.Sort();
And the list would be in the following order:
Upvotes: 2
Views: 242
Reputation: 54457
Store your codes in an array in the order you specify. You can then sort first on the Array.IndexOf the object code values.
int result;
result = Array.IndexOf(codes, this.code).CompareTo(Array.IndexOf(codes, other.code));
if (result == 0)
{
result = // Compare next property.
}
// etc.
return result;
Just note that this is not a full solution but just relating to the codes that are prioritised over the others. You'd first have to make sure that both codes were in the array and handle the situation where they weren't separately.
Upvotes: 1
Reputation: 33381
If it is necessary to implement IComparable
you can use above answer. But you can do it in-place.
objects.OrderBy(
o => o.code == "X5" ? 1 : o.code == "G2" ? 2 : o.code == "H3" ? 3 : 4);
If you want ordering in group (i.e. G2
) you can add ThenBy
as well.
Upvotes: 4
Reputation: 437734
What you want to do is keep a map of "special codes" to their relative weights (that determine sort order among them). Then, when comparing objects:
code1.CompareTo(code2)
This will allow you to maintain the code very easily in the future (if you need to add more special codes or change the weights of those you already have).
So, the code would look somewhat like this:
private static readonly Dictionary<string, int> weights =
new Dictionary<string, int>()
{
{ "X5", 1 },
{ "G2", 2 },
{ "H3", 3 }
}
public int CompareTo(myObject other)
{
var thisIsSpecial = weights.ContainsKey(this.code);
var otherIsSpecial = weights.ContainsKey(other.code);
if (thisIsSpecial && otherIsSpecial)
{
return weights[this.code] - weights [other.code];
}
else if (thisIsSpecial)
{
return -1;
}
else if (otherIsSpecial)
{
return 1;
}
return this.code.CompareTo(other.code);
}
Of course the code needs some improvement (there are no checks for null, it might be a good idea to have a separate comparer instead of hardcoding a static map into the object class, property names should not be all lowercase) but the idea will always be the same.
Upvotes: 2