【问题标题】:C# - sort List<SomeClass> by using custom CompareTo methodC# - 使用自定义 CompareTo 方法对 List<SomeClass> 进行排序
【发布时间】:2016-08-04 10:00:42
【问题描述】:

我有以下类层次结构:

abstract class Product : IComparable
{
    public string Name { get; set; }
    public decimal Price { get; set; }
    public string Barcode { get; set; }

    public int CompareTo(object obj)
    {
        int ret = -1;
        if (String.Compare(this.GetType().Name, obj.GetType().Name,StringComparison.Ordinal) == 0) 
            ret = 0;

        return ret;
    }
}

abstract class Book : Product
{
    public int PagesCount { get; set; }
}

class ProgrammingBook : Book
{
    public string ProgrammingLanguage { get; set; }
}

class CulinaryBook : Book
{
    public string MainIngridient { get; set; }
}

class EsotericBook : Book
{
    public int MininumAge { get; set; }
}
   abstract class Disc : Product
{
    internal enum Content
    {
        Music,
        Video,
        Software
    }

    public Content DiscContent { get; set; }
}

class CdDisc : Disc
{

}

class DvdDisc : Disc
{

}

我尝试使用 IComparable 接口方法 CompareTo 对以下集合进行排序:

 List<Product> products = new List<Product>
        {
            new DvdDisc {Name = "The lord of the rings 2",DiscContent = Disc.Content.Video,Price = 200M,Barcode = "5435443-2"},
            new CdDisc {Name = "Antonio Vivaldi: best picks",Price = 700M, DiscContent = Disc.Content.Music,Barcode = "4543765-565"},
            new CulinaryBook{Name = "Midterranian foods",MainIngridient = "Salmon",PagesCount = 436,Price = 350M,Barcode = "41457561-897"},
            new CdDisc{Name = "Windows XP", DiscContent = Disc.Content.Software, Price = 950M, Barcode = "5433668-4"},
            new EsotericBook{Name = "Russian Freemasonry 1731-2000",MininumAge = 21,PagesCount = 2100,Price = 3000M,Barcode = "6464632-876"},
            new CdDisc {Name = "The best of Mussorgsky",Price = 300M, DiscContent = Disc.Content.Music,Barcode = "5435436-567"},
            new ProgrammingBook{Name = "CLR via C#",PagesCount = 900, Price = 1110M,ProgrammingLanguage = "C#",Barcode = "5546533-2446"},
            new DvdDisc {Name = "The lord of the rings 1",DiscContent = Disc.Content.Video,Price = 200M,Barcode = "54354423-2"},
            new ProgrammingBook{Name = "ASP.NET MVC 4",PagesCount = 800,Price = 1200M,ProgrammingLanguage = "C#",Barcode = "46476573-65"},
            new EsotericBook{Name = "Russian Freemasonry in it's future and past",MininumAge =19, PagesCount = 900, Price = 2342M,Barcode = "3656353-24"},
            new CulinaryBook{Name = "Traditional Polish dishes",MainIngridient = "Red meat",PagesCount = 630,Price = 840,Barcode = "54634234-5"}
        }; products.Sort();

输出列表应如下所示:

1.1 编程书籍
1.2 烹饪书籍
1.3 密教书籍

2.1 按内容排序的 Cd 光盘
2.2 DVD光盘按内容排序

我当前的 CompareTo 方法只完成了部分工作 - 按名称比较类。

【问题讨论】:

  • 由于您需要自定义排序,因此可以选择向产品类添加一个附加属性并按此排序(例如,编程书籍 - SortId = 0,烹饪书籍 SortId = 1,... )。

标签: c# sorting compareto icomparable


【解决方案1】:

这是一个工作示例,将呈现完全相同的输出:

1.1 Programming books 
1.2 Culinary books 
1.3 Esoteric books 

2.1 Cd discs sorted by content 
2.2 DVD discs sorted by content 

我还添加了IComparable&lt;Product&gt;,以便更轻松地与其他产品进行比较。

 abstract class Product : IComparable<Product>
    {
        public string Name { get; set; }
        public decimal Price { get; set; }
        public string Barcode { get; set; }
        protected abstract int InternalSortOrder { get; }
        protected virtual string SortBy { get {return Name;} }


        public int CompareTo(Product obj)
        {
            var sameType = string.Compare(GetType().Name, obj.GetType().Name, StringComparison.Ordinal) == 0;

            var sameBaseType = GetType().BaseType != null && obj.GetType().BaseType != null &&
                               string.Compare(GetType().BaseType.ToString(), obj.GetType().BaseType.ToString(),
                                   StringComparison.Ordinal) == 0;


            // They have the same base type, but not the same type. Order by base type first.
            if (!sameType && !sameBaseType && GetType().BaseType != null && obj.GetType().BaseType != null)
            {
                // Order by base type first.
                return string.Compare(GetType().BaseType.ToString(), obj.GetType().BaseType.ToString(),
                    StringComparison.Ordinal);
            }

            // it's the same base type (eg. book or disc)
            if (sameBaseType)
            {
                // Order by sort order.
                if (obj.InternalSortOrder != this.InternalSortOrder)
                {
                    return InternalSortOrder.CompareTo(obj.InternalSortOrder);
                }
            }

            if (sameType)
            {
                // Same sort order. We sort by name.
                return string.Compare(SortBy, obj.SortBy, StringComparison.Ordinal);
            }

            // Order by Type.
            return string.Compare(GetType().Name, obj.GetType().Name, StringComparison.Ordinal);
        }

    }

    abstract class Book : Product
    {
        public int PagesCount { get; set; }
    }

    class ProgrammingBook : Book
    {
        public string ProgrammingLanguage { get; set; }

        protected override int InternalSortOrder
        {
            get { return 1; }
        }
    }

    class CulinaryBook : Book
    {
        public string MainIngridient { get; set; }

        protected override int InternalSortOrder
        {
            get { return 2; }
        }
    }

    class EsotericBook : Book
    {
        public int MininumAge { get; set; }

        protected override int InternalSortOrder
        {
            get { return 3; }
        }
    }
    abstract class Disc : Product
    {
        internal enum Content
        {
            Music,
            Video,
            Software
        }

        protected override string SortBy
        {
            get { return DiscContent.ToString(); }
        }

        public Content DiscContent { get; set; }
    }

    class CdDisc : Disc
    {
        protected override int InternalSortOrder
        {
            get { return 1; }
        }
    }

    class DvdDisc : Disc
    {
        protected override int InternalSortOrder
        {
            get { return 2; }
        }
    }

更新:

我在Product 中添加了virtual SortBy。默认情况下它将转到Name,但Disc 将返回Content

【讨论】:

  • 我的错。完全错过了。我用 Product 中的虚拟 SortBy 更新了我的答案。它应该可以解决问题。
  • 哇!我对这个问题的解决方案更糟糕。谢谢。
【解决方案2】:

您需要使用 equals 选项

rtn = Primary Sort;
if(rtn =0)
    rtn =secondary Sort;
if(rtn =0)
    rtn =tertiary Sort;

因为你的主要排序似乎是书籍的类型

你会的

rtn = this.GetType().Name.CompareTo(obj.GetType().Name);
if(rtn ==0)
    rtn =this.Name.CompareTo(obj.Name);
return rtn;

如果您的问题是您不希望对类型进行字母排序 然后添加到产品中

public abstract int SortOrder{get;}

并将其用作您的主要排序

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2010-11-07
    • 1970-01-01
    • 1970-01-01
    • 2016-10-28
    • 2012-08-20
    • 1970-01-01
    • 1970-01-01
    • 2013-03-23
    相关资源
    最近更新 更多