2

I have a List<> containing object from a class which has a String property that I want to sort using the following rule:

  1. All objects inside the list which the "code" is X5 should be on top of the list.
  2. All objects inside the list which the "code" is G2 will be after the X5 objects.
  3. All objects inside the list which the "code" is H3 will be after the G2 objects.
  4. All other object should be at the end of the list, sorted alphabetically by the "code".

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:

  1. SAM
  2. JENNIFER
  3. JACK
  4. TOM
3
  • paste your sort logic from CompareTo method Commented Mar 24, 2014 at 23:28
  • 1
    Well, where is the sort logic that goes there? Commented Mar 24, 2014 at 23:28
  • I never wrote a sort logic before and my first attempt was awful so it would not be helpful as much as a good explanation of the problem. Commented Mar 24, 2014 at 23:30

3 Answers 3

4

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.

Sign up to request clarification or add additional context in comments.

2 Comments

@miniBill In-place I mean without implementing IComperable.
In sorting, in place usually means another thing
2

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:

  • if both codes are "special" the comparison result is that of comparing their weights
  • if only one is special then the object having it comes first ("is smaller")
  • if none are special, the comparison result is 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.

2 Comments

This will give the wrong order for Jack/Jennifer - should handle the last code compare == 0 with a name comparison in that case, I believe, if that specific part is important (not sure from question).
@ReedCopsey: Yes, not sure if the sorted example "just happened" to be that way but the rules are clearly stated and at this time they don't mention names.
1

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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.