2009-12-01 20 views
9

quiero para ordenar una lista de persona decirC# - Clasificación utilizando el Método de extensión

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)); 

basan en

public enum CompareOptions 
{ 
    ByFirstName, 
    ByLastName, 
    BySalary 
} 

public enum SortOrder 
{ 
    Ascending, 
    Descending 
} 

usando la expresión lambda lo que es el camino a seguir para la clasificación?

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

Buena pregunta. Está haciendo que los expertos produzcan un código compacto y legible. Todos aprendemos de esto. ¡¡Gracias!! – shahkalpesh

+0

Gracias a todos por la ayuda – user215675

+0

@Shahkalpesh, Tú también me ayudaste para mis viejas preguntas. Me gustaría aprovechar esta oportunidad para agradecerte una vez más. – user215675

Respuesta

8

Parece que está intentando llamar al método Sort en List<T> que tiene un delegado Comparison<T>. Esto requerirá un poco de trabajo porque primero tiene que definir una función de comparación compatible.

primer paso es escribir una función de comparación en función del valor 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(); 
    } 
} 

Por defecto esta función clasificará en orden ascendente. Si quieres que sea descendente, simplemente niega el valor. Así que ahora la escritura SortPeople se puede hacer mediante la siguiente

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

EDITAR

versión que se realiza el 100% en 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

Esto es agradable y limpio, pero realmente no muestra cómo hacerlo en una lambda, que es lo que solicitó OP. –

+0

@Reed Copsey No recomendaría hacerlo en solo un lamba, ya que cada comparación atravesará todos los ifs, no solo una vez para elegir el lambda correcto a usar. – Wilhelm

+0

@Reed, cierto, actualicé la respuesta para incluir una versión lambda pura. – JaredPar

3

Para conseguir que esto funcione en un lambda, el expresión necesita para formar una firma Comparison<T>. Esto tomaría 2 instancias de "Persona". Usted puede hacer esto como:

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

El método de extensión debe tener el tipo de retorno nulo. –

+0

Lo hace.El "resultado de la devolución" es la Compasión que devuelve la orden de clasificación. El método de extensión es simplemente {lst.Sort (...); } –

+0

No, solo digo que el método SortPeople tiene un tipo de devolución de List que no devuelve, pero supongo que solo lo copió de su ejemplo ... –

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

lo que realmente necesita las enumeraciones? No creo que encapsula la lógica de la búsqueda de un método es mucho más claro o más seco que la utilización de métodos de LINQ:

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

etc.

Cuestiones relacionadas