Sorting 'complex' objects...

Hello all,

Just say I have an arraylist of objects (all of the same type) and say these objects are 'Person' objects. So each person has instance variables. such as firstname, surname, etc.

I wish to sort this arraylist of person object references by surname. What is the easiest way to do this

Thank you

Chris




Answer this question

Sorting 'complex' objects...

  • Spyder_Snyper

    Thats really good!

    Thanks Charles I'll test it out.

    Cheers

    Chris



  • chris bax

    Hello,

    Actually I am having a bit of trouble here.

    m_data.Clients.Sort( CompareClientsByName ); -- In this line what is m_data

    I'm a bit lost and have only been able to get the overide 'CompareTo' way to work (it sorste the array list by surname. I can't override it again (in order to sort be first name.

    Any help is appreciated. I have included the code for my CompareTo method.

    public int CompareTo(object o)

    {

    Person other = (Person) o;

    int compareResult = surname.CompareTo(other.surname);

    if (compareResult != 0)

    {

    return compareResult;

    }

    return name.CompareTo(other.name);

    }

    Thank you

    Chris



  • bslim

    Hi,

    You need something like this:

    SomeFunc () {
    m_data
    .Clients.Sort( CompareClientsByName );

    m_data.Clients.Sort( CompareClientsByAge );
    }

    int CompareClientsByAge(Client c1, Client c2)

    {

    return c1.Age - c2.Age;

    }

    int CompareClientsByName(Client c1, Client c2)

    {

    return c1.Name.CompareTo( c2.Name );

    }

    Charles


  • trai_mv

    It looks as if cverdon just copied a snippet of code from his application. "m_data.Clients" refers to a List<> object, so going back to our previous example, that code would be written as :

    List<Person> person = new List<Person>();

    person.Sort( CompareClientsByName );

    In this case, the CompareTo doesn't enter into it at all. We are using the public void Sort (Comparison<T> comparison) overload of Sort, where Comparison<T> is a method which takes two Ts.

    SO, to order by Last Name, First Name:


    public int OrderSurnameGivenname(Person lhs, Person rhs)
    {
    int compareResult = lhs.surname.CompareTo(rhs.surname);
    if (compareResult != 0)
    {
    return compareResult;
    }
    return name.CompareTo(other.name);
    }



  • shailesh_ch

    It works for all values, try it: -5 - -7 = 2 : -5 > -7

    No it doesn't. (For this example, let's work with Int16s) Try: -30000 - +30000 = -60000, but as an Int16, that +5536, a positive result even though -30000 < +30000 (Int32s have the same problem but you have to work with number with a even larger magnatude)

    It's wrong to assume that -1, 0 and 1
    . Yes, that's true....But it's not your program that we're worried about, but someone else's. So, when the other module crashes when it references your assembly, you can try to convince them that you followed the rules and they didn't, or you could just program defensively in the first place, and avoid the problem. This is one of the fundemental principles of library design: The library user should code assuming the looses interpretation of the docs ( <0, 0, >0), while the libray writer should code using the strictest interpreation (-1, 0, +1). That way, if either side slips up, the application still works.



  • Taliesin&amp;#42;

    Thanks very much for that.

    So in our object class to implement the IComparable interface and then implement the compareTo method. So I'm guessing that when we call the sort it will call the CompareTo method we have manually implemented as opposed to the default one. Is this right

    And finally, what if I have a complex object and wish to sort using a particular compareTo method at anyone time An example would be: Sometimes I awant to sort on surname, other times I wish to sort on 'address street name'.

    Is this still the most efficient way

    Thanks

    Chris



  • twonjosh

     

    Yes James guessed it right:

    IDataContainer m_data = new DataContainer();

     

    public class DataContainer : IDataContainer

    {

        private List<Client> m_clients = new List<Client>();

     

        public List<Client> Clients

        {

            get { return m_clients; }

            set { m_clients = value; }

    }

    }

     James Curran wrote:

    1. For some numbers in the range of Int32s (but, admittedly, not in the range of expected human ages), subtracting will give you the wrong answer.
    2. Instead of negative number, zero, positive number, Int32.CompareTo return -1,0,1  which some applications might be expecting (they'd be wrong, but there's not point sticking up for a principle if it breaks the application)
    3. Why deviate from a standard for such a tiny micro-optimization The time saved during a sort will never be significant, but the confusion it causes some maintence programmer will probably be.
     
    1. It works for all values, try it: -5 - -7 = 2 : -5 > -7
    2. It's wrong to assume that -1, 0 and 1 is the only values that can be returned. The documentation planely states
       msdn wrote:
       

      Return Value

      A 32-bit signed integer that indicates the relative order of the objects being compared. The return value has these meanings:

      Value

      Meaning

      Less than zero

      This instance is less than obj.

      Zero

      This instance is equal to obj.

      Greater than zero

      This instance is greater than obj.

       


      http://msdn2.microsoft.com/en-gb/library/system.icomparable.compareto.aspx

    3. I agree, but if it works in all cases and it respects the standards there is no problem in implementing integer comparison with a simple - operation

    Regards,
    Charles


  • Anand Raman - MSFT

    Make your Person class implement IComparable<Person>.  Here's an example I've knocked up quickly:

    class Person : IComparable<Person>
    {
       string name;
       string surname;

       public Person(string name, string surname)
       {
          this.name = name;
          this.surname = surname;
       }

       public int CompareTo(Person other)
       {
         int compareResult = surname.CompareTo(other.surname);
         if (compareResult != 0)
         {
            return compareResult;
         }
         return name.CompareTo(other.name);
       }
    }

    public void TestSort()
    {
        List<Person> person = new List<Person>();

        person.Add(new Person("Dave", "Jones"));
        person.Add(new Person("Andy", "Jones"));
        person.Add(new Person("Barry", "Anderson"));
        person.Sort();
    }


  • Jim Altrichter

    int CompareClientsByAge(Client c1, Client c2)

    {

    return c1.Age - c2.Age;

    }

    While I'm all in favor of a good shortcut, I'd still write that as:

    int CompareClientsByAge(Client c1, Client c2)

    {

    return c1.Age.CompareTo(c2.Age);

    }

    for a few reasons:

    1. For some numbers in the range of Int32s (but, admittedly, not in the range of expected human ages), subtracting will give you the wrong answer.
    2. Instead of negative number, zero, positive number, Int32.CompareTo return -1,0,1 which some applications might be expecting (they'd be wrong, but there's not point sticking up for a principle if it breaks the application)
    3. Why deviate from a standard for such a tiny micro-optimization The time saved during a sort will never be significant, but the confusion it causes some maintence programmer will probably be.


  • Sorting 'complex' objects...