6

I am writing an address book program. I have each person's details stored in a List<Person>. I need to be able to sort this list by last name (using first name if there are ties) or by post code.

So far I have this:

public class Person
{
    public string LastName { get; set; }
    public string FirstName { get; set; }
    public string PostCode { get; set; }
    // etc..
}

public class AddressBook
{
    public List<Person> People { get; set; }

    // asc: ascending or descending
    // column: the property to use when sorting
    //         (in my case either LastName or Postcode)
    public void Sort(bool asc, string column)
    {
        // What should I put here?
    }

    // etc...
}

I have tried using the ICompare and IComparable interfaces but I am just not getting it.

How do I write the Sort method?

2
  • What version of C# / .NET are you using? Commented Mar 21, 2012 at 11:39
  • I tried to clean up your question so that it's easier to read. I hope it's OK. Commented Mar 21, 2012 at 13:18

3 Answers 3

9

Assuming:

 List<Person> personList;

then with Linq:

 IEnumerable<Person> orderedByLastName = personList.OrderBy(p => p.LastName)
Sign up to request clarification or add additional context in comments.

2 Comments

Thanks Spender, I am clearly missing something (need to do a bit more reading into linq) as this is not working for me at all. When I run the tests through the sort method the List is not sorted at all in anyway.
@user1243505: That's because this - and Mark's answer too - don't do in-place sorting. They return a new object which contains the content's of the original list in the sorted order.
5

You can try using the LINQ extension methods OrderBy, OrderByDescending, ThenBy and ThenByDescending:

using System.Linq;

// ...

public void Sort(bool asc, string column)
{
    switch (column)
    {
        case "LastName":
            People = People.OrderBy(x => x.LastName).ThenBy(x => x.FirstName).ToList();
            break;
        case "PostCode":
            People = People.OrderBy(x => x.PostCode).ToList();
            break;
        default:
            // error handling
    }

    if (!asc)
    {
        People.Reverse();
    }
}

You could also look at Dynamic LINQ which would simplify this code.

2 Comments

Thanks for your reply. As I said below, I need to look into linq a lot more as i dont understand how to get your code to sort the list. Thank you for your help though.
@user1243505: If I were you I'd invest in my future and learn LINQ. It's much simpler and easier to use. A small investment in your own education now will save you a lot of time in the long run, and make you more a valuable programmer in the future. But it's your life, your career, your choice...
3

You can use an implementation of IComparer<T>:

public class PersonComparer : IComparer<Person>
{
    private readonly bool _sortAscending;
    private readonly string _columnToSortOn;

    public PersonComparer(bool sortAscending, string columnToSortOn)
    {
        _sortAscending = sortAscending;
        _columnToSortOn = columnToSortOn;
    }

    public int Compare(Person x, Person y)
    {
        if(x == null && y == null) return 0;
        if(x == null) return ApplySortDirection(-1);
        if(y == null) return ApplySortDirection(1);

        switch(_columnToSortOn)
        {
            case "LastName":
                return ApplySortDirection(SortByName(x, y));
                break;
            case "PostCode":
                return ApplySortDirection(SortByPostCode(x, y));
                break;
            default:
                throw new ArgumentOutOfRangeException(
                    string.Format("Can't sort on column {0}",
                    _columnToSortOn));
        }
    }

    private int SortByPostCode(Person x, Person y)
    {
        return x.PostCode.CompareTo(y.PostCode);
    }

    private int SortByName(Person x, Person y)
    {
        var lastNameResult = x.LastName.CompareTo(y.LastName);
        if(lastNameResult != 0)
            return lastNameResult;
        return x.FirstName.CompareTo(y.FirstName);
    }

    private int ApplySortDirection(int result)
    {
        return _sortAscending ? result : (result * -1);
    }
}

You would use it in the Sort method of your AddressBook class like this, assuming People is a List<Person>:

public void Sort(bool asc, string column)
{
    People.Sort(new PersonComparer(asc, column));
}

This code has the benefit of using an in-place sort.

1 Comment

Works perfectly. AND... (even better) I understand it... Thank you very much!

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.