Question

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
    }
}

Je ne sais pas quel genre de tri c'est là le code d'admission 1203 Dr Sheldon apparaît en haut de la liste après le tri ??? je me attendais 801802803 et 1203 ... Quelqu'un peut-il expliquer?

Était-ce utile?

La solution

Les chiffres que vous comparez ne sont pas traités comme des numéros, mais comme des chaînes! Et avec les chaînes de la lettre « 1 » vient avant « 8 », de sorte que le plus grand nombre apparaît d'abord parce que lorsqu'ils sont traités sous forme de texte, l'ordre est différent.

Je vous recommande de convertir ce domaine à un int si vous souhaitez traiter comme un.

Modifier :. Pour votre question modifier le texte (champ contient aussi maintenant des lettres), vous aurez besoin à la logique d'écriture de comparaison personnalisée pour les comparer dans l'ordre que vous désirez

Par exemple, je suppose que vous voulez que la logique comme ceci:

  1. Code Divisé en nombre et lettres.
  2. Comparer uniquement des chiffres (int).
  3. Si des pièces de numéro sont les mêmes pour les deux valeurs, comparez le reste sous forme de chaîne.

Mettre en œuvre cette logique (ou quelle que soit la logique que vous voulez vraiment) dans votre méthode CompareTo et vous aurez l'ordre désiré.

peut-être comme le code pour cette logique ceci:

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
}

Autres conseils

Vous triez les chaînes et non des nombres. La CompareTo chaîne ne prend pas en compte la longueur.

EDIT (Pour votre question Edited). Lors du tri des chaînes qui commencent par le nombre, la méthode de tri CompareTo volonté à peine donner les résultats escomptés que tout ce qu'il fait est classement par ordre alphabétique

String "1203" est inférieur à "801". Vous pouvez essayer de convertir des chaînes en nombres avant la comparaison (si elles représentent des valeurs numériques essentiellement)

Ceci est la fonctionnalité attendue comme d'autres l'ont noté.
Si vous voulez l'ordre comme 801r, 802x, 892k, 1203a le faire

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

Si vous voulez le garder 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
}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top