2009-12-01 3 views
9

Je veux trier une liste de personnes disentC# - Méthode d'extension à l'aide de tri

List<Person> persons=new List<Person>(); 
persons.Add(new Person("Jon","Bernald",45000.89)); 
persons.Add(new Person("Mark","Drake",346.89)); 
persons.Add(new Person("Bill","Watts",456.899)); 

basé sur

public enum CompareOptions 
{ 
    ByFirstName, 
    ByLastName, 
    BySalary 
} 

public enum SortOrder 
{ 
    Ascending, 
    Descending 
} 

en utilisant l'expression lambda quelle est la voie à suivre pour le tri?

public static List<Person> SortPeople(this List<Person> lst, 
    CompareOptions opt1,SortOrder ord) 

     { 
      lst.Sort((p,op1,op2)=>{ how to apply lambda expression here}); 
     } 
+1

Bonne question. Vous faites en sorte que les experts produisent un code compact et lisible. Nous apprenons tous de cela. Merci!! – shahkalpesh

+0

Merci à tous pour l'aide – user215675

+0

@Shahkalpesh, Toi aussi m'a bien aidé pour mes anciennes questions. Je profite de l'occasion pour te remercier encore une fois. – user215675

Répondre

8

On dirait que vous essayez d'appeler la méthode de tri sur List<T> qui prend un délégué Comparison<T>. Cela demandera un peu de travail car vous devez d'abord définir une fonction de comparaison compatible.

La première étape consiste à écrire une fonction de comparaison basée sur la valeur CompareOptions

private static Comparison<Person> Create(CompareOptions opt) { 
    switch (opt) { 
    case CompareOptions.ByFirstName: (x,y) => x.FirstName.CompareTo(y.FirstName); 
    case CompareOptions.ByLastName: (x,y) => x.LastName.CompareTo(y.LastName); 
    case CompareOptions.BySalary: (x,y) => x.Salary - y.Salary; 
    default: throw new Exception(); 
    } 
} 

Par défaut, cette fonction tri dans l'ordre croissant. Si vous voulez qu'il soit descendant, annulez simplement la valeur. Donc, en train d'écrire SortPeople peut être fait par la suite

public static List<Person> SortPeople(
    this List<Person> list, 
    CompareOptions opt1, 
    SortOrder ord)) 
    var original = Create(opt1); 
    var comp = original; 
    if(ord == SortOrder.Descending) { 
    comp = (x,y) => -(orig(x,y)); 
    } 
    list.Sort(comp); 
} 

EDIT

version qui se fait à 100% dans un lambda

public static List<Person> SortPeople(
    this List<Person> list, 
    CompareOptions opt1, 
    SortOrder ord)) 

    list.Sort((x,y) => { 
    int comp = 0; 
    switch (opt) { 
     case CompareOptions.ByFirstName: comp = x.FirstName.CompareTo(y.FirstName); 
     case CompareOptions.ByLastName: comp = x.LastName.CompareTo(y.LastName); 
     case CompareOptions.BySalary: comp = x.Salary.CompareTo(y.Salary); 
     default: throw new Exception(); 
    } 
    if (ord == SortOrder.Descending) { 
     comp = -comp; 
    } 
    return comp; 
    }); 
} 
+0

C'est beau et propre, mais ça ne montre pas vraiment comment le faire dans un lambda, ce que demande l'OP. –

+0

@Reed Copsey Je ne recommanderais pas de le faire en un seul lamba, car chaque comparaison transverse tous les ifs, pas seulement une fois pour choisir le bon lambda à utiliser. – Wilhelm

+0

@Reed, vrai, j'ai mis à jour la réponse pour inclure une version lambda pure. – JaredPar

3

Pour que cela fonctionne dans un lambda, la expression doit former une signature Comparison<T>. Cela prendrait 2 instances "Person". Vous pouvez le faire comme:

public static void SortPeople(
    this List<Person> lst, CompareOptions opt1,SortOrder ord) 
{ 
    lst.Sort((left, right) => 
      { 
       int result; 
       // left and right are the two Person instances 
       if (opt1 == CompareOptions.Salary) 
       { 
        result = left.Salary.CompareTo(right.Salary); 
       } 
       else 
       { 
        string compStr1, compStr2; 
        if (opt1 == CompareOptions.FirstName) 
        { 
          compStr1 = left.FirstName; 
          compStr2 = right.FirstName; 
        } 
        else 
        { 
          compStr1 = left.LastName; 
          compStr2 = right.LastName; 
        } 
        result = compStr1.CompareTo(compStr2); 
       } 
       if (ord == SortOrder.Descending) 
        result *= -1; 
       return result; 
      }); 
} 
+0

La méthode d'extension doit avoir le type de retour void. –

+0

C'est le cas.Le "résultat de retour" est la comparaison renvoyant l'ordre de tri. La méthode d'extension est juste {lst.Sort (...); } –

+0

Non, je dis juste que la méthode SortPeople a un type de retour de Liste qui ne retourne pas, mais je suppose que vous venez de le copier de son exemple ... –

2
using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 

namespace ConsoleApplication2 
{ 
    class Program 
    { 
    static void Main(string[] args) 
    { 
     List<Person> persons = new List<Person>(); 
     persons.Add(new Person("Jon", "Bernald", 45000.89)); 
     persons.Add(new Person("Mark", "Drake", 346.89)); 
     persons.Add(new Person("Bill", "Watts", 456.899)); 

     persons.SortPeople(CompareOptions.ByFirstName, SortOrder.Ascending); 

     persons.ForEach(p => Console.WriteLine(p.ToString())); 

     persons.SortPeople(CompareOptions.ByFirstName, SortOrder.Descending); 

     persons.ForEach(p => Console.WriteLine(p.ToString())); 

     persons.SortPeople(CompareOptions.ByLastName, SortOrder.Ascending); 

     persons.ForEach(p => Console.WriteLine(p.ToString())); 

     persons.SortPeople(CompareOptions.ByLastName, SortOrder.Descending); 

     persons.ForEach(p => Console.WriteLine(p.ToString())); 

     persons.SortPeople(CompareOptions.BySalary, SortOrder.Ascending); 

     persons.ForEach(p => Console.WriteLine(p.ToString())); 

     persons.SortPeople(CompareOptions.BySalary, SortOrder.Descending); 

     persons.ForEach(p => Console.WriteLine(p.ToString())); 

     Console.ReadLine(); 
    } 
} 

public static class Extensions 
{ 
    public static void SortPeople(this List<Person> lst, CompareOptions opt1,SortOrder ord){ 
     lst.Sort((Person p1, Person p2) => 
      { 
       switch (opt1) 
       { 
        case CompareOptions.ByFirstName: 
         return ord == SortOrder.Ascending ? p1.FirstName.CompareTo(p2.FirstName) : p2.FirstName.CompareTo(p1.FirstName); 
        case CompareOptions.ByLastName: 
         return ord == SortOrder.Ascending ? p1.LastName.CompareTo(p2.LastName) : p2.LastName.CompareTo(p1.LastName); 
        case CompareOptions.BySalary: 
         return ord == SortOrder.Ascending ? p1.Salary.CompareTo(p2.Salary) : p2.Salary.CompareTo(p1.Salary); 
        default: 
         return 0; 
       } 
      }); 
    } 
} 

public class Person 
{ 
    public double Salary { get; set; } 
    public string FirstName { get; set; } 
    public string LastName { get; set; } 

    public Person(string first, string last, double salary) 
    { 
     this.Salary = salary; 
     this.FirstName = first; 
     this.LastName = last; 
    } 

    public override string ToString() 
    { 
     return string.Format("{0} {1} has a salary of {2}", this.FirstName, this.LastName, this.Salary); 
    } 
} 

public enum CompareOptions { ByFirstName, ByLastName, BySalary } 
public enum SortOrder { Ascending, Descending } 

}

6

Avez-vous vraiment besoin des énumérations? Je ne pense pas que l'encapsulation de votre logique de recherche dans une méthode est beaucoup plus claire ou plus sec que tout en utilisant des méthodes de LINQ:

persons.OrderBy(p => p.FirstName); 
persons.OrderByDescending(p => p.Salary); 

etc.