2010-09-15 3 views
4

J'ai besoin de pouvoir trier une collection de clients qui contient une propriété de chaîne numérique.Tri d'une collection de chaînes numériques

Comment puis-je trier la collection ci-dessous par code dans un ordre numérique. Encore une fois le code est une chaîne.

  class Program 
      { 
       static void Main(string[] args) 
       { 
       SortableObservableCollection<Customer> customerList = new SortableObservableCollection<Customer>(); 
       customerList.Add(new Customer() {Name = "Jo", Code = "1"}); 
       customerList.Add(new Customer() { Name = "Jo", Code = "10" }); 
       customerList.Add(new Customer() { Name = "Jo", Code = "11" }); 
       customerList.Add(new Customer() { Name = "Jo", Code = "9" }); 
       customerList.Add(new Customer() { Name = "Jo", Code = "7" }); 
       customerList.Add(new Customer() { Name = "Jo", Code = "12" }); 
       customerList.Add(new Customer() { Name = "Jo", Code = "13" }); 
       customerList.Add(new Customer() { Name = "Jo", Code = "2" }); 
       customerList.Add(new Customer() { Name = "Jo", Code = "5" }); 
       customerList.Add(new Customer() { Name = "Jo", Code = "7" }); 

       //Order them by Code How 
       } 
      } 

      public class Customer 
      { 
       public string Name { get; set; } 
       public string Code { get; set; } 
      } 

Merci pour toutes suggestions

+0

Avez-vous accès à la classe Customer ou s'agit-il d'une bibliothèque tierce? –

+0

Cet article pourrait vous intéresser: http://blogs.msdn.com/b/michkap/archive/2005/01/05/346933.aspx –

Répondre

13

Option 1: mettre en œuvre IComparer<Customer> et analyser le code dans ce

Option 2: utiliser LINQ pour faire le même chose:

customerList = customerList.OrderBy(c => int.Parse(c.Code)).ToList(); 

Option 3: modifiez la classe Customer afin qu'une valeur numérique soit stockée en tant que type numérique :)

EDIT: comme indiqué, une exception sera émise si vous lui donnez un client avec un code non numérique.

En outre, j'appelle ToList() parce que je supposais que vous en aviez toujours besoin pour être une liste. Si vous avez juste besoin d'itérer sur les résultats par ordre, puis utilisez:

IEnumerable<Customer> ordered = customerList.OrderBy(c => int.Parse(c.Code)); 

Notez que si vous itérer sur cette deux fois, cependant, il effectuera l'analyse et du tri deux fois trop.

+0

Cela fonctionne uniquement si la propriété de code est analysée avec succès en numérique. – TalentTuner

+0

Excellent tout fonctionne avec int.Parse. J'accepterai une fois que le site me le laissera. 6 mins – user9969

+0

@saurabh: Oui, s'il y a des données invalides, ça explosera. Je ne mettrais pas la validation des données à * cette * étape si ... Je l'aurais mise beaucoup plus tôt. Bien sûr, s'il est valable d'avoir des chaînes non numériques pour un client, cela ne fonctionnerait pas ... mais j'espère que la question aurait été formulée différemment. –

-2

Essayez LINQ aux objets:

var result = from c in customerList 
      orderby Int.Parse(c.Code) 
      select c; 
+1

Cela va trier "100" avant "2". –

+0

Cela fonctionnerait, mais je crois que puisque c'est une chaîne, '10' trierait au-dessus de' 1' – Nate

+0

Supervision. Merci à vous deux, @Jon Skeet et @Nate Bross. J'ai corrigé ma réponse. – rkellerm

2

Dans quelle mesure avez-vous confiance que le code est (a) numérique et (b) présent?

var sortedList = customerList.OrderBy(c => int.Parse(c.Code)); 

Si vous avez des doutes, essayez une autre approche

Func<string, bool> isInteger = s => { int temp; return int.TryParse(s, out temp); }; 
var query = customerList.OrderBy(c => isInteger(c.Code) ? int.Parse(c.Code) : int.MaxValue); 

Ou pour réduire le nombre de attemtps pour analyser la valeur et de maintenir la logique dans un délégué:

Func<string, int> intParser = input => 
{ 
    int result; 
    if (!int.TryParse(input, out result)) 
     return int.MaxValue; 

    return result; 
}; 

var query = customerList.OrderBy(c => intParser(c.Code)); // .ToList() if you wish 

Remarque : J'utilise int.MaxValue pour déplacer les entrées non entières vers l'arrière de la ligne. Vous pouvez choisir une autre valeur en fonction de l'endroit où vous pourriez vouloir ces objets.

+0

celui-ci est beaucoup acceptable. +1 pour prendre note de l'alphabet et de la chaîne numérique – Rye

6

Si les touches sont toujours que des chiffres et ces chiffres sont toujours convertibles en ints alors il est assez simple. Convertissez-les en ints.

var sorted = from customer in customerList orderby Int32.ParseInt(customer.Code) select customer; 

Si l'un d'entre eux n'est pas ints alors cela se bloquera.

Une autre façon de le faire est de pad la chaîne avec zéros:

var sorted = from customer in customerList orderby PadToTenDigits(customer.Code) select customer; 

où PadToTenDigits est une méthode laissée en exercice, qui tourne « 1 » en « 0000000001 » et « 1000 » en "0000001000", et ainsi de suite.

Si vous devez faire un vrai tri "numérique" sur des codes complexes, où, disons, le code "A300-B" trie avant "A1000-XYZ", alors vous avez un problème plus difficile entre vos mains.L'astuce est de diviser le code en "parties" et de faire un tri stable sur chaque partie. Fondamentalement, un tri radix.

+0

J'aime l'approche PadToTenDigits. Il semble effectuer un peu plus vite (environ 3.5x sur ma construction) que ma méthode d'entiers deux fois parsing. C'est aussi un délégué/une fonction assez simple pour écrire. –

+0

Bien sûr, l'avantage de la façon dont je l'ai fait est que (a) il compare seulement les nombres, et non potentiellement '000000ABCD', et vous obtenez un peu de contrôle si l'entrée non numérique/vide est triée vers l'avant (int .MinValue) ou back (int.MaxValue) de la ligne. Là encore, PadToTen pourrait potentiellement être codé pour atteindre ces mêmes objectifs. –

+0

@Anthony: Il est possible de réécrire votre approche pour n'utiliser qu'un seul appel de 'int.TryParse' - cela signifie simplement une expression lambda un peu plus laide (un bloc complet lambda, qui ne fonctionnerait donc pas dans une expression de requête). Cela ne générerait pas autant d'ordures, je suppose. D'un autre côté, je fais toujours * comme * le pad à dix chiffres approche :) –

Questions connexes