.NET/C#中对自定义对象集合进行自定义排序的方法

一个集合可否排序,要看系统知不知道排序的规则,像内建的系统类型,int ,string,short,decimal这些,系统知道怎么排序,而如果一个集合里面放置的是自定义类型,比如自己定义了一个Car类型,要把它排序,系统是不知道怎么办的。

那么,如何告知系统排序的规则呢?有以下几种方法:

1:对类实现IComparable接口,示例如下:

[csharp] view plain copy

print?

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. namespace 对集合对象进行排序
  6. {
  7. class Product : IComparable
  8. {
  9. public string Name
  10. {
  11. get;
  12. private set;
  13. }
  14. public decimal Price
  15. {
  16. get;
  17. private set;
  18. }
  19. public Product(string name, decimal price)
  20. {
  21. Name = name;
  22. Price = price;
  23. }
  24. public Product()
  25. {
  26. }
  27. public static List<Product> GetSampleProduct()
  28. {
  29. return new List<Product>
  30. {
  31. new Product { Name = "Watch", Price = 12345.56m },
  32. new Product { Name = "Knife", Price = 224.50m },
  33. new Product { Name = "EZpe", Price = 12.50m },
  34. new Product { Name = "ETorch", Price = 58.5m } };
  35. }
  36. public override string ToString()
  37. {
  38. return string.Format("{0} : {1}", Name, Price);
  39. }
  40. int IComparable.CompareTo(object obj)
  41. {
  42. Product temp = (Product)obj;
  43. return this.Name.CompareTo(temp.Name);
  44. }
  45. }
  46. class Program
  47. {
  48. static void Main(string[] args)
  49. {
  50. List<Product> ProductSample = Product.GetSampleProduct();
  51. foreach(Product tmp in ProductSample)
  52. {
  53. Console.WriteLine(tmp);
  54. }
  55. Console.WriteLine();
  56. ProductSample.Sort();
  57. foreach(Product tmp in ProductSample)
  58. {
  59. Console.WriteLine(tmp);
  60. }
  61. Console.ReadKey();
  62. }
  63. }
  64. }

其中最主要的是这句:

  class Product :IComparable

跟这句:

    int IComparable.CompareTo(object obj)
        {
            Product temp = (Product)obj;
            return this.Name.CompareTo(temp.Name);
        }

就是实现了IComparable.CompareTo()这个方法。然后就可以直接调用 SomeProductList.Sort();方法来进行排序。

2,指定IComparer  类的对象。

[csharp] view plain copy

print?

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. namespace SortTeset2
  6. {
  7. class Product
  8. {
  9. public string Name
  10. {
  11. get;
  12. private set;
  13. }
  14. public decimal Price
  15. {
  16. get;
  17. private set;
  18. }
  19. public Product(string name, decimal price)
  20. {
  21. Name = name;
  22. Price = price;
  23. }
  24. public Product()
  25. {
  26. }
  27. public static List<Product> GetSampleProduct()
  28. {
  29. return new List<Product>
  30. {
  31. new Product { Name = "Watch", Price = 12345.56m },
  32. new Product { Name = "Knife", Price = 224.50m },
  33. new Product { Name = "Rope", Price = 12.50m },
  34. new Product { Name = "ETorch", Price = 58.5m }
  35. };
  36. }
  37. public override string ToString()
  38. {
  39. return string.Format("{0} : {1}", Name, Price);
  40. }
  41. }
  42. class ProductNameComparer : IComparer<Product>
  43. {
  44. public int Compare(Product first, Product second)
  45. {
  46. return first.Name.CompareTo(second.Name);
  47. }
  48. }
  49. class Program
  50. {
  51. static void Main(string[] args)
  52. {
  53. List<Product> ProductSample = Product.GetSampleProduct();
  54. foreach(Product tmp in ProductSample)
  55. {
  56. Console.WriteLine(tmp);
  57. }
  58. Console.WriteLine();
  59. ProductSample.Sort(new ProductNameComparer());
  60. foreach(Product tmp in ProductSample)
  61. {
  62. Console.WriteLine(tmp);
  63. }
  64. }
  65. }
  66. }

这儿我们新定义了一个类:ProductNameComparer,这个类实现了泛型接口:IComparer<Product>,然后在

ProductSample.Sort(new ProductNameComparer());

语句中我们提供了一个比较器对象。

这种方法看上去不如直接实现ICompareable接口来得简洁。

这种方法可以用匿名方法进行改进:

[csharp] view plain copy

print?

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. namespace SortTeset3
  6. {
  7. class Product
  8. {
  9. public string Name
  10. {
  11. get;
  12. private set;
  13. }
  14. public decimal Price
  15. {
  16. get;
  17. private set;
  18. }
  19. public Product(string name, decimal price)
  20. {
  21. Name = name;
  22. Price = price;
  23. }
  24. public Product()
  25. {
  26. }
  27. public static List<Product> GetSampleProduct()
  28. {
  29. return new List<Product>
  30. {
  31. new Product { Name = "Watch", Price = 12345.56m },
  32. new Product { Name = "Knife", Price = 224.50m },
  33. new Product { Name = "Rope", Price = 12.50m },
  34. new Product { Name = "ETorch", Price = 58.5m }
  35. };
  36. }
  37. public override string ToString()
  38. {
  39. return string.Format("{0} : {1}", Name, Price);
  40. }
  41. }
  42. class Program
  43. {
  44. static void Main(string[] args)
  45. {
  46. List<Product> ProductSample = Product.GetSampleProduct();
  47. foreach(Product tmp in ProductSample)
  48. {
  49. Console.WriteLine(tmp);
  50. }
  51. Console.WriteLine();
  52. ProductSample.Sort(delegate(Product first, Product second)
  53. {
  54. return first.Name.CompareTo(second.Name);
  55. });
  56. foreach(Product tmp in ProductSample)
  57. {
  58. Console.WriteLine(tmp);
  59. }
  60. }
  61. }
  62. }

这一次,不用定义那个类,然后使用它的方法了,而是直接填充delegate接口。

这种方法还可以进一步用Lambda表达式改进,如下:

[csharp] view plain copy

print?

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. namespace SortTeset3
  6. {
  7. class Product
  8. {
  9. public string Name
  10. {
  11. get;
  12. private set;
  13. }
  14. public decimal Price
  15. {
  16. get;
  17. private set;
  18. }
  19. public Product(string name, decimal price)
  20. {
  21. Name = name;
  22. Price = price;
  23. }
  24. public Product()
  25. {
  26. }
  27. public static List<Product> GetSampleProduct()
  28. {
  29. return new List<Product>
  30. {
  31. new Product { Name = "Watch", Price = 12345.56m },
  32. new Product { Name = "Knife", Price = 224.50m },
  33. new Product { Name = "Rope", Price = 12.50m },
  34. new Product { Name = "ETorch", Price = 58.5m }
  35. };
  36. }
  37. public override string ToString()
  38. {
  39. return string.Format("{0} : {1}", Name, Price);
  40. }
  41. }
  42. class Program39
  43. {
  44. static void Main(string[] args)
  45. {
  46. List<Product> ProductSample = Product.GetSampleProduct();
  47. foreach(Product tmp in ProductSample)
  48. {
  49. Console.WriteLine(tmp);
  50. }
  51. Console.WriteLine();
  52. ProductSample.Sort((first, second) => first.Name.CompareTo(second.Name));
  53. foreach(Product tmp in ProductSample)
  54. {
  55. Console.WriteLine(tmp);
  56. }
  57. }
  58. }
  59. }

变态的是,还可以进一步改进,使用扩展方法,如下:

[csharp] view plain copy

print?

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. namespace SortTeset3
  6. {
  7. class Product
  8. {
  9. public string Name
  10. {
  11. get;
  12. private set;
  13. }
  14. public decimal Price
  15. {
  16. get;
  17. private set;
  18. }
  19. public Product(string name, decimal price)
  20. {
  21. Name = name;
  22. Price = price;
  23. }
  24. public Product()
  25. {
  26. }
  27. public static List<Product> GetSampleProduct()
  28. {
  29. return new List<Product>
  30. {
  31. new Product { Name = "Watch", Price = 12345.56m },
  32. new Product { Name = "Knife", Price = 224.50m },
  33. new Product { Name = "Rope", Price = 12.50m },
  34. new Product { Name = "ETorch", Price = 58.5m }
  35. };
  36. }
  37. public override string ToString()
  38. {
  39. return string.Format("{0} : {1}", Name, Price);
  40. }
  41. }
  42. class Program39
  43. {
  44. static void Main(string[] args)
  45. {
  46. List<Product> ProductSample = Product.GetSampleProduct();
  47. foreach(Product tmp in ProductSample)
  48. {
  49. Console.WriteLine(tmp);
  50. }
  51. Console.WriteLine();
  52. foreach(Product tmp in ProductSample.OrderBy(p => p.Name))
  53. {
  54. Console.WriteLine(tmp);
  55. }
  56. }
  57. }
  58. }

“这里似乎调用了一个OrderBy方法,但查阅一下MSDN,就会发现这个方法在List<Product>中根本不存在。之所以能调用它,是由于存在一个扩展方法。这里实际不再是"原地"对列表进行排序,而只是按特定的顺序获取列表的内容。有的时候,你需要更改实际的列表;但有的时候,没有任何副作用的排序显得更"善解人意"。重点在于,现在的写法更简洁,可读性更好(当然是在你理解了语法之后)。我们的想法是"列表按名称排序",现在的代码正是这样做的。并不是"列表通过将一个产品的名称与另一个产品的名称进行比较来排序",就像C# 2代码所做的那样。也不是使用知道如何将一个产品与另一个产品进行比较的另一个类型的实例来按名称排序。这种简化的表达方式是C# 3的核心优势之一。既然单独的数据查询和操作是如此的简单,那么在执行更大规模的数据处理时,仍然可以保持代码的简洁性和可读性,这进而鼓励开发者以一种"以数据为中心"的方式来观察世界。”

最后这两步的语法,绝对是一个会用其它语言比如C/C++,VB的人所无法明白的,C#进化速度真是快。。。。。。。

关于排序,暂时还不知道有没有其它的方法,日后再补记。

参考书籍:《C#与.NET3.5高级程序设计》,《深入解析C#》(C# in depth) 。

另外,这篇文章还提到了另外两种更深入的做法:1,自定义排序,可以提供一个接口,接受一个排序指标,然后对指定List进行排序,2,用LINQ的orderby子句实现排序。

?

以自定义方式可以实现的更多的控制,例如我们重构BookComparison:

 

// Release : code01, 2009/04/12

 

 // Author  : Anytao, http://www.anytao.com/

 

 // List    : BookComparison.cs

 

public
 class  BookComparison : IComparer<Book>{ 

 

    privateComparisonType type;

 

    publicBookComparison(ComparisonType type)

 

    {        this.type = type;    }

 

    publicint
Compare(Book x, Book y)

 

    {

 

        switch(this.type) 

 

       {

 

            caseComparisonType.Price:

 

                returnx.Price.CompareTo(y.Price);

 

                break;

 

            caseComparisonType.PublishDate:

 

                returnx.PublishDate.CompareTo(y.PublishDate);

 

                break;

 

            default:

 

                break;

 

        }

 

        return0;

 

    }

 

}

 

添加一个ComparisonType结构,在BookComparson初始化时决定Comparison的方式:

 

//04 Sort by custom comparison: BookComparison

 

bs.Books.Sort(newBookComparison(ComparisonType.PublishDate).Compare); 

 

结论

 

自定义Comparison为实现更好的Sort控制,提供了很好的扩展机制。在我们的实际应用中,对于例如BookStore这样的具体应用而言,我更推荐以LINQ的OrderBy来实现,例如:

 

//05 Sort by Linq

 

var list = from c in
bs.Books

 

           orderby c.PublishDate ascending

 

           select c;

 

foreach(var item inlist)

 

{

 

    Console.WriteLine(string.Format("{0}:{1}, {2}", item.Name, item.Price, item.PublishDate.ToString()));

 

}

 

orderby子句可以选择任意的排序条件,同时ascending或者descending控制升序和降序。

原文地址:https://www.cnblogs.com/amylis_chen/p/8253817.html

时间: 2024-08-01 13:43:16

.NET/C#中对自定义对象集合进行自定义排序的方法的相关文章

Java中利用MessageFormat对象实现类似C# string.Format方法格式化

我们在写C#代码的时候常常会使用到string.Format("待格式化字符串{0},{1},....",参数1,参数2,...),来格式化字符串,特别是拼接字符的时候,这种方式使得代码更为直观清楚. 最近使用java时候却java的string.Format与c#重点string.Format用法不一样,java中的string.format更类似于C语言的sprintf()方法 例如: String str=null; str=String.format("Hello,%

C#高级知识点概要(3) - 特性、自动属性、对象集合初始化器、扩展方法、Lambda表达式和Linq查询

1.特性(Attributes) 特性(Attributes),MSDN的定义是:公共语言运行时允许你添加类似关键字的描述声明,叫做attributes, 它对程序中的元素进行标注,如类型.字段.方法和属性等.Attributes和Microsoft .NET Framework文件的元数据保存在一起,可以用来向运行时描述你的代码,或者在程序运行的时候影响应用程序的行为.例如,在一个方法前标注[Obsolete]特性,则调用该方法时VS则会提示该方法已过期的警告,如下图: 又如,在.Net Re

nuxtjs在vue组件中使用window对象编译报错的解决方法

我们知道nuxtjs是做服务端渲染的,他有很多声明周期是运行在服务端的,以及正常的vue声明周期mounted之前均是在服务端运行的,那么服务端是没有比如window对象的location.navagitor等,以及H5的FormData()方法,所以当你在created之前使用这些时,会报错,那么如何处理呢? 1.自己的写的函数里包含window等 因为nuxt为SSR框架,所以其编译打包时会区分服务端渲染还是客户端渲染(即浏览器),在vue文件中使用window对象报错的原因是,webpac

Collections集合(对象集合)的排序

需要用自己写的comparator Comparator<AQIRankCity> comparator = new Comparator<AQIRankCity>() { public int compare(AQIRankCity o1, AQIRankCity o2) { return o1.getRank() > o2.getRank() ? 1 : -1; } };

hibernate中对象集合的保存

一.在java web设计中经常使用对象进行操作,在hibernate中对象集合的保存(一对多) 1需要进行如下步骤: 1) 设计数据表关系 2)引入jar包,需要注意引入数据库connector 3)写实体类 4)配置映射文件和hibernate.cfg.xml 2例子如下: 员工和部门的关系,多个员工属于一个部门,一个部门有多个员工.可以在员工表上设置一个外键解决一对多的关系. 2.1)创建表 CREATE TABLE employee( id INT PRIMARY KEY AUTO_IN

《java入门第一季》之HashSet存储自定义对象问题以及注意事项

上一篇http://blog.csdn.net/qq_32059827/article/details/51578158 写到存储字符串类型的时候出现了无序,而且这个无序不是随机那种无序,它是有一定存储规律的.上次存储的是字符串,那么这里看看存储自定义对象是不是也是同样的规律.其实这里有着很多的问题需要讨论. 存储自定义对象,代码写了出来: import java.util.HashSet; public class HashSetDemo2 { public static void main(

js自定义对象 (转)

原文地址:https://sjolzy.cn/js-custom-object.html 29 March 2010 9:53 Monday by 小屋 javascript进阶之对象篇 一,概述 在Java语言中,我们可以定义自己的类,并根据这些类创建对象来使用,在Javascript中,我们也可以定义自己的类,例如定义User类.Hashtable类等等. 目前在Javascript中,已经存在一些标准的类,例如Date.Array.RegExp.String.Math.Number等等,这

JavaScript 类的定义和引用 JavaScript高级培训 自定义对象

在Java语言中,我们可以定义自己的类,并根据这些类创建对象来使用,在Javascript中,我们也可以定义自己的类,例如定义User类.Hashtable类等等. 一,概述 在Java语言中,我们可以定义自己的类,并根据这些类创建对象来使用,在Javascript中,我们也可以定义自己的类,例如定义User类.Hashtable类等等. 目前在Javascript中,已经存在一些标准的类,例如Date.Array.RegExp.String.Math.Number等等,这为我们编程提供了许多方

详解Javascript中的Array对象

基础介绍 创建数组 和Object对象一样,创建Array也有2种方式:构造函数.字面量法. 构造函数创建 使用构造函数的方式可以通过new关键字来声明,如下所示: 12 var arr = new Array();console.log(arr);//[] 当然也可以不通过new关键字来声明: 12 var arr = Array();console.log(arr); //[] 如果知道数组元素的个数,也可以直接传入数字表示元素个数: 12 var arr2 = new Array(5);c