c#如何实现IComparable接口

摘要:
示例9-14使用System对整数和员工数组进行排序;使用System.Collections.Generic;使用System.Text//Randomr=newRandom(),生成整数和员工ID的随机数;

实现IComparable接口

像所有集合类一样,List实现了Sort()方法,它允许您对所有实现了IComparable接口的对象进行排序。在下一个例子中,您将修改Employee类以实现IComparable:

public class Employee : IComparable

实现IComparable接口,Employee对象必须提供CompareTo()方法:

public int CompareTo(Employee rhs)

{

   return this.empID.CompareTo(rhs.empID);

}

CompareTo()方法把Employee做为参数。我们知道使用Employee是因为这是一个类型安全的集合。当前Employee对象必须把它自己跟做为参数传递进来的Employee进行对比,如果返回-1,表示它小于参数,如果大于参数则返回1,如果两者相等则返回0。这意味着决定大于、小于、等于的是Employee。在本例中,您委托成员empId进行比较。empId成员是一个int类型,并使用了整数类型默认的CompareTo()方法,以对比两个值之间的大小。

System.Int32类实现了Icomparable接口,所以您可以把比较的职责委托给整数类型。

您现在准备对员工数组列表(empList)进行排序,为了查看排序是否正常工作,您需要随机地添加整数和Employee实例到它们各自的数组中。创建随机数,需要实例化Random类;调用Random对象的Next()方法产生随机数。Next()方法是一个重载方法;一种版本允许您传递一个整数值,表示您想要的最大随机数。在本例中,您将传递10来产生一个0到10之间的随机数:(译者注:参数为10,最大的随机数只能为9)

Random r = new Random();

r.Next(10);

例9-14创建了一个整型数组和一个Employee数组,并给两者填充随机数,并打印它们的值。随后排序数组并打印新值。

例9-14 排序整数和employee数组

using System;
using System.Collections.Generic;
using System.Text;

namespace IComparable
{
   // 一个简单的用于存储在数组中的类
   public class Employee : IComparable<Employee>
   {
      private int empID;
      public Employee( int empID )
      {
         this.empID = empID;
      }
      public override string ToString( )
      {
         return empID.ToString( );
      }
      public bool Equals( Employee other )
      {
         if ( this.empID == other.empID )
         {
            return true;
         }
         else
         {
            return false;
         }
      }
      // Employee使用整数默认的CompareTo方法
      public int CompareTo( Employee rhs )
      {
         return this.empID.CompareTo( rhs.empID );
      }
   }
   public class Tester
   {
      static void Main( )
      {
         List<Employee> empArray = new List<Employee>( );
         List<Int32> intArray = new List<Int32>( );
         // 产生整数和employee的ID的随机数
         Random r = new Random( );
         // 填充数组
         for ( int i = 0; i < 5; i++ )
         {
            // 添加随机的employee的id
            empArray.Add( new Employee( r.Next( 10 ) + 100 ) );
            // 添加随机的整数
            intArray.Add( r.Next( 10 ) );
         }
         // 显示整型数组中的所有内容
         for ( int i = 0; i < intArray.Count; i++ )
         {
            Console.Write( "{0} ", intArray[i].ToString( ) );
         }
         Console.WriteLine( "\n" );
         // 显示Employee数组中的所有内容
         for ( int i = 0; i < empArray.Count; i++ )
         {
            Console.Write( "{0} ", empArray[i].ToString( ) );
         }
         Console.WriteLine( "\n" );
         // 整型数组排序
         intArray.Sort( );
         for ( int i = 0; i < intArray.Count; i++ )
         {
            Console.Write( "{0} ", intArray[i].ToString( ) );
         }
         Console.WriteLine( "\n" );
         // employee数组排序并显示
         //原文的下面这两句应该注释掉,现在还没用到
         //Employee.EmployeeComparer c = Employee.GetComparer( );
         //empArray.Sort(c);
         empArray.Sort( );
         // 显示Employee数组中的所有内容
         for ( int i = 0; i < empArray.Count; i++ )
         {
            Console.Write( "{0} ", empArray[i].ToString( ) );
         }
         Console.WriteLine( "\n" );
      }
   }
}


 

输出结果:

4 5 6 5 7

108 100 101 103 103

4 5 5 6 7

100 101 103 103 108

输出显示整型数组和Employee数组产生的是随机数。排序后,显示的是已经进行排序后的值。

9.6.2 实现IComparer接口
当您在List中调用Sort(),默认的IComparer(译者注:这里可能是错误,应该为IComparable)实现被调用,它调用IComparable所实现的CompareTo()方法对List内的每个元素进行快速排序。

当您想控制排列方式时,可以自由地创建自己的IComparer实现。在下一个例子中,将在Employee中添加第二个字段:yearsOfSvc。您希望在List中按两种字段empID或yearsOfSvc来对Employee对象进行排序。

为了达到这个目的,需要创建IComparer的实现,用于传递给List中Sort()方法的参数。这个IComparer类是EmployeeComparer,它让Employee对象知道如何进行排序。

EmployeeComparer类有一个WhichComparison属性,它是Employee. EmployeeComparer.ComparisonType类型:

public Employee.EmployeeComparer.ComparisonType WhichComparison

{

   get{return whichComparison;}

   set{whichComparison = value;}

}

ComparisonType是一个枚举类型,它有两个值:empID或yearsOfSvc(指示您希望按员工ID还是工龄进行排序):

public enum ComparisonType

{

   EmpID,

   YearsOfService

};

在调用Sort()方法之前,创建EmployeeComparer的实例并设置它的ComparisonType属性:

Employee.EmployeeComparer c = Employee.GetComparer();

c.WhichComparison=Employee.EmployeeComparer.ComparisonType.EmpID;

empArray.Sort(c);

调用Sort()方法之时,List会调用EmployeeComparer中的Compare方法,并把当前要对比的字段通过WhickComparison属性传递给Employee.CompareTo()方法:

public int Compare( Employee lhs, Employee rhs )

{

    return lhs.CompareTo( rhs, WhichComparison );

}

Employee对象必须实现一个自定义的CompareTo()方法,用于获得比较方式并按照要求进行对比:

public int CompareTo(Employee rhs,

    Employee.EmployeeComparer.ComparisonType which)

{

   switch (which)

   {

      case Employee.EmployeeComparer.ComparisonType.EmpID:

         return this.empID.CompareTo(rhs.empID);

      case Employee.EmployeeComparer.ComparisonType.Yrs:

         return this.yearsOfSvc.CompareTo(rhs.yearsOfSvc);

   }

   return 0;

}

例9-15是这个例子的完整代码。为了简化例子,整型数组已经被移除,用于输出的Employee的ToString()方法也增加了代码以让您看得到排序的效果。

例9-15 按员工的ID和工龄进行排序


using System;
using System.Collections.Generic;
using System.Text;

namespace IComparer
{
    public class Employee : IComparable<Employee>
    {
        private int empID;
        private int yearsOfSvc = 1;
        public Employee(int empID)
        {
            this.empID = empID;
        }
        public Employee(int empID, int yearsOfSvc)
        {
            this.empID = empID;
            this.yearsOfSvc = yearsOfSvc;
        }
        public override string ToString()
        {
            return "ID:" + empID.ToString() +
                ". Years of Svc:" + yearsOfSvc.ToString();
        }
        public bool Equals(Employee other)
        {
            if (this.empID == other.empID)
            {
                return true;
            }
            else
            {
                return false;
            }
        }
        //静态方法,用于获取一个Comparer对象
        public static EmployeeComparer GetComparer()
        {
            return new Employee.EmployeeComparer();
        }
        public int CompareTo(Employee rhs)
        {
            return this.empID.CompareTo(rhs.empID);
        }
        //通过自定义comparer来调用指定的实现
        public int CompareTo(Employee rhs,
            Employee.EmployeeComparer.ComparisonType which)
        {
            switch (which)
            {
                case Employee.EmployeeComparer.ComparisonType.EmpID:
                    return this.empID.CompareTo(rhs.empID);
                case Employee.EmployeeComparer.ComparisonType.Yrs:
                    return this.yearsOfSvc.CompareTo(rhs.yearsOfSvc);
            }
            return 0;
        }
        //实现IComparer接口的嵌套类
        public class EmployeeComparer : IComparer<Employee>
        {
            private Employee.EmployeeComparer.ComparisonType
                whichComparison;
            //比较方式枚举
            public enum ComparisonType
            {
                EmpID,
                Yrs
            };
            public bool Equals(Employee lhs, Employee rhs)
            {
                return this.Compare(lhs, rhs) == 0;
            }
            public int GetHashCode(Employee e)
            {
                return e.GetHashCode();
            }
            public int Compare(Employee lhs, Employee rhs)
            {
                return lhs.CompareTo(rhs, WhichComparison);
            }
            public Employee.EmployeeComparer.ComparisonType
                WhichComparison
            {
                get { return whichComparison; }
                set { whichComparison = value; }
            }
        }
    }
    public class Tester
    {
        static void Main()
        {
            List<Employee> empArray = new List<Employee>();
            Random r = new Random();
            for (int i = 0; i < 5; i++)
            {
                //添加一个随机的员工ID
                empArray.Add(new Employee(
                    r.Next(10) + 100, r.Next(20)));
            }
            //显示Employee数组的所有内容
            for (int i = 0; i < empArray.Count; i++)
            {
                Console.Write("\n{0} ", empArray[i].ToString());
            }
            Console.WriteLine("\n");
            //排序并显示Employee数组
            Employee.EmployeeComparer c = Employee.GetComparer();
            c.WhichComparison =
                Employee.EmployeeComparer.ComparisonType.EmpID;
            empArray.Sort(c);
            //显示Employee数组的所有内容
            for (int i = 0; i < empArray.Count; i++)
            {
                Console.Write("\n{0} ", empArray[i].ToString());
            }
            Console.WriteLine("\n");

            c.WhichComparison = Employee.EmployeeComparer.ComparisonType.Yrs;
            empArray.Sort(c);
            for (int i = 0; i < empArray.Count; i++)
            {
                Console.Write("\n{0} ", empArray[i].ToString());
            }
            Console.WriteLine("\n");
        }
    }
}


 

输出结果:

ID: 103. Years of Svc: 11

ID: 108. Years of Svc: 15

ID: 107. Years of Svc: 14

ID: 108. Years of Svc: 5

ID: 102. Years of Svc: 0

ID: 102. Years of Svc: 0

ID: 103. Years of Svc: 11

ID: 107. Years of Svc: 14

ID: 108. Years of Svc: 15

ID: 108. Years of Svc: 5

ID: 102. Years of Svc: 0

ID: 108. Years of Svc: 5

ID: 103. Years of Svc: 11

ID: 107. Years of Svc: 14

ID: 108. Years of Svc: 15

第一块输出显示的是Employee对象被加进List时的情形。员工ID值和工龄是随机顺序的。第二块显示的是按员工ID排序后的结果,第三块显示的是按工龄排序后的结果。

如果您如例9-11那样创建自己的集合,并希望实现IComparer,可能需要确保所有放在列表中的类型都实现了IComparer接口(这样他们才有可能被排序),这可以通过前面讲述的约束来实现。

免责声明:文章转载自《c#如何实现IComparable接口》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇可视化机器学习工具软件的比较分析研究matlab读取csv文件数据并绘图下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

h5接入微信分享sdk,报错Cannot read property of undefined (reading 'title')

直接下载jweixin-1.6.0.js文件,引入文件 import wx from './jweixin-1.6.0.js'; 解决方法: 将jweixin-1.6.0.js文件中的this改为window就可以了 其他方法,参考: https://blog.csdn.net/illlllllllllll/article/details/112789...

SmartSql漫谈

最近在看smartSql源码,兄弟写的。写的很不错取取经。 记录下一些学习的东西,刚开始我先不系统的写了,随意一点哈,我看的差不多再给大家一个模块一个模块系统的写。 public T ExecuteScalar<T>(RequestContext context) { T result =...

Java排序(一)实现类的排序

  类按照类中的某一个属性(或者多个属性)来对类的对象进行排序,   有 3 种方法可以实现,   1、Collections.sort 排序重写 compare方法   2、实现Comparable<T>接口   3、通过自定义比较器类的方式实现排序   以下,实现一个类的排序 class Person{ public Strin...

Android View 绘制流程之 DecorView 与 ViewRootImpl

一年多以前,曾经以为自己对 View 的添加显示逻辑已经有所了解了,事后发现也只是懂了些皮毛而已。经过一年多的实战,Android 和 Java 基础都有了提升,是时候该去看看 DecorView 的添加显示。 View 的绘制系列文章: Android View 绘制流程之 DecorView 与 ViewRootImpl Android View 的...

Spring Boot 面试题

1、列举一些SpringBoot特性 1、创建独立的Spring项目 2、内置Tomcat和Jetty容器 3、提供一个starter POMs来简化Maven配置 4、提供了一系列大型项目中常见的非功能性特性,如安全、指标,健康检测、外部配置等 5、完全没有代码生成和xml配置文件 2、有什么常用的Spring Boot启动器?spring-boot...

Scrapy爬虫的暂停和启动

scrapy的每一个爬虫,暂停时可以记录暂停状态以及爬取了哪些url,重启时可以从暂停状态开始爬取过的URL不在爬取 实现暂停与重启记录状态 方法一: 1、首先cd进入到scrapy项目里(当然你也可以通过编写脚本Python文件直接在pycharm中运行) 2、在scrapy项目里创建保存记录信息的文件夹 3、执行命令:   scrapy craw...