我的IComparable实现在哪里出错了?

时间:2011-01-11 08:07:26

标签: c# sorting icomparable

namespace SortableLists
{
    using System;
    using System.Collections.Generic;

    public class Program
    {
        private static void Main() {
            var list = new List<ListItem>
                           {
                               new ListItem {AdmissionCode = "801r", Name = "Rajesh Koothrappali", RollNumber = 54},
                               new ListItem {AdmissionCode = "892k", Name = "Leonard Leakey Hofstadter", RollNumber = 34},
                               new ListItem {AdmissionCode = "1203a", Name = "Sheldon Lee Cooper", RollNumber = 46},
                               new ListItem {AdmissionCode = "802x", Name = "Howard Wolowitz", RollNumber = 98}
                           };
            list.ForEach(x => Console.WriteLine(x.RollNumber + ","+x.Name + "," + x.AdmissionCode));

            Console.Write("\n");
            list.Sort();
            list.ForEach(x => Console.WriteLine(x.RollNumber + "," + x.Name + "," + x.AdmissionCode));

            Console.ReadKey();
        }
    }

    public class ListItem : IComparable<ListItem>
    {
        public int RollNumber { get; set; }
        public string Name { get; set; }
        public string AdmissionCode { get; set; }

        #region Implementation of IComparable<in ListItem>

        public int CompareTo(ListItem other) {
            return AdmissionCode.CompareTo(other.AdmissionCode);
        }

        #endregion
    }
}

我不知道这是什么样的排序这是排序代码1203谢尔顿博士在排序后出现在列表顶部的地方???我期待801,802,803和1203 ...有人可以解释一下吗?

5 个答案:

答案 0 :(得分:4)

您要比较的数字不会被视为数字而是字符串!对于字符串,字母“1”出现在“8”之前,因此较大的数字首先出现,因为当被视为文本时,顺序是不同的。

如果您希望将此字段视为一个字段,我建议您将此字段转换为int

编辑:对于您编辑过的问题(字段现在还包含字母),您需要编写自定义比较逻辑,以便按照您想要的顺序进行比较。

例如,我想你希望逻辑是这样的:

  1. 将代码拆分为数字&amp;字母。
  2. 仅比较数字(如int)。
  3. 如果两个值的数字部分相同,则将其余部分作为字符串进行比较。
  4. 在您的CompareTo方法中实现此逻辑(或您真正想要的任何逻辑),您将获得所需的订单。

    这种逻辑的代码可能是这样的:

    public class ListItem : IComparable<ListItem>
    {
        public int RollNumber { get; set; }
        public string Name { get; set; }
        public string AdmissionCode { get; set; }
    
        private static readonly char[] Numbers = new[]
        {
            '0',
            '1',
            '2',
            '3',
            '4',
            '5',
            '6',
            '7',
            '8',
            '9'
        };
    
        #region Implementation of IComparable<in ListItem>
        public int CompareTo(ListItem other)
        {
            // Assumes AdmissionCode is in ####ABC format,
            // with at least one number and any amount of letters.
            string myNumberPart, myRemainingPart;
            string otherNumberPart, otherRemainingPart;
    
            SplitAdmissionCode(AdmissionCode, out myNumberPart, out myRemainingPart);
            SplitAdmissionCode(other.AdmissionCode, out otherNumberPart, out otherRemainingPart);
    
            int myNumber = int.Parse(myNumberPart);
            int otherNumber = int.Parse(otherNumberPart);
    
            int result = myNumber.CompareTo(otherNumber);
    
            // Numbers are different.
            if (result != 0)
                return result;
    
            // Numbers are same. Use text compare for the remaining part.
            return myRemainingPart.CompareTo(otherRemainingPart);
        }
    
        private void SplitAdmissionCode(string code, out string numbersPart, out string remainingPart)
        {
            int lastNumberIndex = code.LastIndexOfAny(Numbers);
    
            numbersPart = code.Substring(0, lastNumberIndex + 1);
    
            if (lastNumberIndex == code.Length - 1)
                remainingPart = "";
            else
                remainingPart = code.Substring(lastNumberIndex + 1);
        }
        #endregion
    }
    

答案 1 :(得分:3)

您正在排序字符串而不是数字。字符串CompareTo不考虑长度。

编辑(对于您编辑的问题):在对以数字开头的字符串进行排序时,CompareTo方法的排序很难给出预期的结果,因为它所做的就是按字母顺序排列。

答案 2 :(得分:0)

字符串“1203”小于“801”。您可以尝试在比较之前将字符串转换为数字(如果它们本质上代表数字值)

答案 3 :(得分:0)

这是其他人注意到的预期功能 如果您想要801r, 802x, 892k, 1203a这样的订单,请执行此操作

public class ListItem : IComparable<ListItem>
{
    public int RollNumber { get; set; }
    public string Name { get; set; }
    public string AdmissionCode { get; set; }

    public int CompareTo(ListItem other) {
        return ExtractNumbers(this.AdmissionCode).CompareTo(ExtractNumbers(other.AdmissionCode));
    }
    private int ExtractNumbers(string expr) {
        return Convert.ToInt32(String.Join(null,System.Text.RegularExpressions.Regex.Split(expr, "[^\\d]")));
    }
}

答案 4 :(得分:0)

如果你想保持简单:

public class ListItem : IComparable<ListItem>
{
    public int RollNumber { get; set; }
    public string Name { get; set; }
    public string AdmissionCode { get; set; }

    #region Implementation of IComparable<in ListItem>

    public int CompareTo(ListItem other)
    {
        return this.AdmissionCode.Length != other.AdmissionCode.Length
            ? this.AdmissionCode.Length.CompareTo(other.AdmissionCode.Length)
            : this.AdmissionCode.CompareTo(other.AdmissionCode);
    }

    #endregion
}