2009-12-01 15 views
9

voglio ordinare un elenco di persona direC# - Ordinamento utilizzando Metodo di estensione

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

basano su

public enum CompareOptions 
{ 
    ByFirstName, 
    ByLastName, 
    BySalary 
} 

public enum SortOrder 
{ 
    Ascending, 
    Descending 
} 

utilizzando un'espressione lambda qual è la strada da percorrere per l'ordinamento?

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

Buona domanda. Stai facendo in modo che gli esperti producano codice compatto e leggibile. Tutti impariamo da questo. Grazie!! – shahkalpesh

+0

Grazie a tutti per l'aiuto – user215675

+0

@Shahkalpesh, anche tu mi hai aiutato bene per le mie vecchie domande. Vorrei cogliere l'occasione per ringraziarti ancora una volta. – user215675

risposta

8

Sembra che si sta tentando di chiamare il metodo Sort su List<T> che prende un delegato Comparison<T>. Ciò richiederà un po 'di lavoro perché devi prima definire una funzione di confronto compatibile.

primo passo è scrivere una funzione di confronto sulla base del valore 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(); 
    } 
} 

Per default questa funzione ordinare in ordine crescente. Se vuoi che scenda, annulla semplicemente il valore. Così ora la scrittura SortPeople può essere fatto con la seguente

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

versione che è fatto al 100% in 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

Questo è bello e pulito, ma in realtà non mostra come farlo in una lambda, che è ciò che l'OP chiedeva. –

+0

@Reed Copsey Non consiglierei di farlo in una sola lamba, poiché ogni confronto attraverserà tutti i ifs, non solo una volta per scegliere il lambda corretto da usare. – Wilhelm

+0

@Reed, vero, ho aggiornato la risposta per includere una versione lambda pura. – JaredPar

3

Per farlo funzionare in un lambda, la espressione deve formare una firma Comparison<T>. Ciò richiederebbe 2 istanze "Persona". Si potrebbe fare questo tipo:

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

Il metodo di estensione deve avere il tipo di reso void. –

+0

Lo fa.Il "risultato di ritorno" è Comparsion che restituisce l'ordinamento. Il metodo di estensione è solo {lst.Sort (...); } –

+0

No, sto solo dicendo che il metodo SortPeople ha un tipo di ritorno di Lista che non restituisce, ma suppongo che tu l'abbia appena copiato dal suo esempio ... –

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

avete veramente bisogno le enumerazioni? Non credo che incapsula la logica di ricerca in un metodo è molto più chiaro o più secco rispetto solo utilizzando metodi di LINQ:

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

ecc

Problemi correlati