Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
365 views
in Technique[技术] by (71.8m points)

c# - LINQ Custom Sort

I want an alphabetic sort with one exception.
There is a Group with a Name = "Public" and an ID = "0" that I want first.
(would rather use ID = 0)
After that then sort the rest by Name.
This does not return public first.

public IEnumerable<GroupAuthority> GroupAuthoritysSorted 
{ 
   get 
   { 
       return GroupAuthoritys.OrderBy(x => x.Group.Name); 
   } 
}

What I want is:

return GroupAuthoritys.Where(x => x.ID == 0)
       UNION 
       GroupAuthoritys.Where(x => x.ID > 0).OrderBy(x => x.Group.Name);

GroupAuthority has a public property Group and Group has Public properties ID and Name.

I used basically the accepted answer

using System.ComponentModel;

namespace SortCustom
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            TestSort();
        }
        private void TestSort()
        {
            List<CustomSort> LCS = new List<CustomSort>();
            LCS.Add(new CustomSort(5, "sss"));
            LCS.Add(new CustomSort(6, "xxx"));
            LCS.Add(new CustomSort(4, "xxx"));
            LCS.Add(new CustomSort(3, "aaa"));
            LCS.Add(new CustomSort(7, "bbb"));
            LCS.Add(new CustomSort(0, "pub"));
            LCS.Add(new CustomSort(2, "eee"));
            LCS.Add(new CustomSort(3, "www"));
            foreach (CustomSort cs in LCS) System.Diagnostics.Debug.WriteLine(cs.Name);
            LCS.Sort();
            foreach (CustomSort cs in LCS) System.Diagnostics.Debug.WriteLine(cs.Name);
        }
    }
    public class CustomSort : Object, INotifyPropertyChanged, IComparable<CustomSort>
    {
        public event PropertyChangedEventHandler PropertyChanged;
        public void OnPropertyChanged(PropertyChangedEventArgs e)
        {
            if (PropertyChanged != null) PropertyChanged(this, e);
        }
        private Int16 id;
        private string name;
        public Int16 ID { get { return id; } }
        public String Name { get { return name; } }
        public int CompareTo(CustomSort obj)
        {
            if (this.ID == 0) return -1;
            if (obj == null) return 1;
            if (obj is CustomSort)
            {
                CustomSort comp = (CustomSort)obj;
                if (comp.ID == 0) return 1;
                return string.Compare(this.Name, comp.Name, true);
            }
            else
            {
                return 1;
            }
        }
        public override bool Equals(Object obj)
        {
            // Check for null values and compare run-time types.
            if (obj == null) return false;
            if (!(obj is CustomSort)) return false;
            CustomSort comp = (CustomSort)obj;
            return (comp.ID == this.ID); 
        }
        public override int GetHashCode()
        {
            return (Int32)ID;
        }
        public CustomSort(Int16 ID, String Name)
        {
            id = ID;
            name = Name;
        }
    }
}
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

You need to use a comparison function, they are functions that from two instances of your type return an integer that return 0 if both are equals, a negative value if the first is less than the second and a positive value if the first is greater than the second.

MSDN has a nice table that is easier to follow than text (StackOverflow still doesn't support tables in 2014)

IComparer<T>

Most sort methods accept a custom comparer implementation of type IComparer<T> you should create one encapsulating your custom rules for Group :

class GroupComparer : IComparer<Group>
{
    public int Compare(Group a, Group b)
    {
        if (a != null && b != null && (a.Id == 0 || b.Id == 0))
        {
            if (a.Id == b.Id)
            {
                // Mandatory as some sort algorithms require Compare(a, b) and Compare(b, a) to be consitent
                return 0; 
            }
            return a.Id == 0 ? -1 : 1;
        }

        if (a == null || b == null)
        {
            if (ReferenceEquals(a, b))
            {
                return 0;
            }
            return a == null ? -1 : 1;
        }
        return Comparer<string>.Default.Compare(a.Name, b.Name);
    }
}

Usage:

items.OrderBy(_ => _, new GroupAuthorityComparer());



IComparable<T>

If it is the only way to compare Group instances you should make it implement IComparable<T> so that no aditional code is needed if anyone want to sort your class :

class Group : IComparable<Group>
{
    ...

    public int CompareTo(Group b)
    {
        if (b != null && (Id == 0 || b.Id == 0))
        {
            if (Id == b.Id)
            {
                // Mandatory as some sort algorithms require Compare(a, b) and Compare(b, a) to be consitent
                return 0; 
            }
            return Id == 0 ? -1 : 1;
        }

        return Comparer<string>.Default.Compare(Name, b.Name);
    }   
}

Usage:

items.OrderBy(_ => _.Group);

The choice between one way or the other should be done depending on where this specific comparer is used: Is it the main ordering for this type of item or just the ordering that should be used in one specific case, for example only in some administrative view.

You can even go one level up and provide an IComparable<GroupAuthority> implementation (It's easy once Group implement IComparable<Group>):

class GroupAuthority : IComparable<GroupAuthority>
{
    ...

    public int CompareTo(GroupAuthority b)
    {
        return Comparer<Group>.Default.Compare(Group, b.Group);
    }
}

Usage:

items.OrderBy(_ => _);

The advantage of the last one is that it will be used automatically, so code like: GroupAuthoritys.ToList().Sort() will do the correct thing out of the box.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...