2011-01-11 3 views
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 Доктор Шелдон появляется наверху списка после сортировки ??? я ожидал 801 802 803 и 1203 ... может кто-нибудь объяснить?Где моя реализация IComparable идет не так?

ответ

4

Цифры, которые вы сравниваете, не считаются цифрами, а строками! И со строками буква «1» появляется перед «8», поэтому большее число появляется первым, потому что, когда обрабатывается как текст, порядок отличается.

Я рекомендую вам преобразовать это поле в int, если вы хотите рассматривать его как одно.

Редактировать: для вашего отредактированного вопроса (поле также содержит буквы) вам нужно будет написать собственную логику сравнения, чтобы сравнить их в желаемом порядке.

Например, я полагаю, вы хотите, чтобы логика быть так:

  1. Split код в число & букв.
  2. Сравнение номеров только (как int).
  3. Если частичные числа одинаковы для обоих значений, сравните остальные как строку.

Реализуйте эту логику (или любую другую логику, которая вам действительно нужна) в методе 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 
} 
3

Вы сортируете строки, а не цифры. Строка CompareTo не учитывает длину.

EDIT (для отредактированного вопроса): При сортировке строк, которые начинаются с цифрами, сортировка CompareTo метода будет вряд ли даст ожидаемые результаты, все это делает в алфавитном порядке.

+0

Я не смотрю на них как номера .... редактирование вопрос сейчас – Perpetualcoder

0

Строка "1203" меньше, чем "801". Вы можете попытаться преобразовать строки в числа перед сравнением (если они представляют значения чисел по существу)

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]"))); 
    } 
} 
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 
}