4
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 Sheldon博士排序后出现在列表顶部???我期待 801,802,803 和 1203 ......谁能解释一下?

4

5 回答 5

4

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

I recommend you convert this field to an int if you wish to treat it as one.

Edit: for your edited question (field now also contains letters), you will need to write custom comparison logic to compare them in the order you desire.

For example, I imagine you want the logic to be like this:

  1. Split code into number & letters.
  2. Compare numbers only (as int).
  3. If number parts are the same for both values, compare the rest as string.

Implement this logic (or whatever logic you really want) in your CompareTo method and you'll have your desired order.

The code for such logic might be like this:

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
}
于 2011-01-11T08:10:06.827 回答
3

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

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

于 2011-01-11T08:09:02.757 回答
0

String "1203" is less than "801". You may try to convert strings into numbers before comparison(if they represent number values essentially)

于 2011-01-11T08:11:33.670 回答
0

This is the expected functionality as others have noted.
If you want the order like 801r, 802x, 892k, 1203a do this

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]")));
    }
}
于 2011-01-11T08:33:25.650 回答
0

If you want to keep it simple:

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
}
于 2011-01-11T09:55:50.630 回答