开发者

Custom Sorting (IComparer on three fields)

I have a person class with three fields, Title, Name, Gender and I would like to create a Custom Sort for it to sort it first by Title, then by Name and then by Gender ascending:

public class SortPerson : IComparer
    {
        public int Compare(object x, object y)
        {
            (…)
        }
    }

I know how to do this for only one variable to compare against: But How would I have to proceed with three?

public class SortPerson : IComparer
        {

int IComparer.Compare(object a, object b)
   {
      Person p1=(Person)a;
      Person p2=(Person)b;
      if (p1.T开发者_如何学Citle > p2.Title)
         return 1;
      if (p1.Title < p2.Title)
         return -1;
      else
         return 0;
   }
}

Many Thanks,


//Assuming all the fields implement IComparable
int result = a.field1.CompareTo(b.field1);
if (result == 0)
  result = a.field2.CompareTo(b.field2);
if (result == 0)
  result = a.field3.CompareTo(b.field3);
return result;


I don't know what's the use you have for the comparer, but maybe you could use instead of a comparer the "order by" LINQ statement, which allows to sort by various fields:

var orderedListPersons =
    from p in listPersons
    orderby p.Title, p.Name, p.Gender
    select person;

will order listPersons the way you want. You can also use the LINQ OrderBy and ThenBy methods for the same thing with a different syntax:

var orderedlistPersons = listPersons.OrderBy(p => p.Title).ThenBy(p => p.Name).ThenBy(p => p.Gender);


Sort on one field at a time, in order of precedence, only continuing to the next field if the previous field compare resulted in 0 (fields equal). See the following for an example of a 2-field sort.

http://csharp.2000things.com/2010/10/30/135-implementing-icomparable-to-allow-sorting-a-custom-type/


One way would be to implement the interface like this.

public class Person : IComparer<Person>
{
    public string Titel { get; set; }

    int IComparer<Person>.Compare(Person x, Person y)
    {
        if (x is null)
            throw new ArgumentNullException(nameof(x));
        if (y is null)
            throw new ArgumentNullException(nameof(y));

        return x.Titel.CompareTo(y.Titel);                      
    }
}

Sometimes though you might have a Little more Control ober how you'd like to sort. Sure you can use linq however then you'd have to make a list garbage allocations loss in speed and it is really not to hard to do when implementing the IComparer interface.

Have a look at the below sample and you will see that you can combine as many properties as you need.

public class Person : IComparable<Person>, IComparer<Person>
{
    public string Titel { get; set; }

    public string FirstName { get; set; }

    public string LastName { get; set; }

    public DateTime? SomeOptionalValue { get; set; }

    int IComparer<Person>.Compare(Person x, Person y)
    {       
        return (x as IComparable).CompareTo(y);
    }

    int IComparable<Person>.CompareTo(Person other)
    {
        if (other is null)
            throw new ArgumentNullException(nameof(other));
        int result = this.Titel.CompareTo(other.Titel);

        //chain the other properties in the order you'd like to
        //have them sorted. 
        if (result == 0)
            result = this.FirstName.CompareTo(other.FirstName);

        if (result == 0)
            result = this.LastName.CompareTo(other.LastName);

        //use optional values as well as call the compare implementation on a class
        if (result == 0 && SomeOptionalValue.HasValue && other.SomeOptionalValue.HasValue)
            result = DateTime.Compare(this.SomeOptionalValue.Value, other.SomeOptionalValue.Value);

        return result;
    }
}


If repeated code gives you the ick and you're wanting code that you can write once and apply to various different classes, you can implement it in a generic extension-method way like this.

Here's my static extension methods class:

public static class SortabilityExtensions
{
    public static int CompareTo<T>(this T a, T b, params Func<T, IComparable>[] getVals) where T : IComparable<T>
    {
        foreach (var getVal in getVals)
        {
            int comparison = getVal(a).CompareTo(getVal(b));
            if (comparison != 0)
                return comparison;
        }
        return 0;
    }
}

And then to get my IComparable implementation in my Person class as per the original post, with sorting by Title then Name then Gender, my CompareTo can look like this:

public int CompareTo(Person other)
{
    return this.CompareTo(other, a => a.Title, a => a.Name, a => a.Gender);
}
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜