C # - сортировка с использованием метода расширения - PullRequest
10 голосов
/ 01 декабря 2009

Я хочу отсортировать список людей, которые говорят

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

на основе

public enum CompareOptions
 {
    ByFirstName,
    ByLastName,
    BySalary
 }

 public enum SortOrder
 {
   Ascending,
   Descending
 }

используя лямбда-выражение, как можно сортировать?

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

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

Ответы [ 4 ]

10 голосов
/ 01 декабря 2009

Похоже, вы пытаетесь вызвать метод Sort для List<T>, для которого требуется делегат Comparison<T>. Это потребует немного работы, потому что сначала вы должны определить совместимую функцию сравнения.

Первый шаг - написать функцию сравнения на основе значения 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();
  }
}

По умолчанию эта функция сортируется в порядке возрастания. Если вы хотите, чтобы он был убывающим, просто отрицайте значение. Итак, теперь написание SortPeople можно сделать следующим

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

РЕДАКТИРОВАТЬ

Версия, которая сделана на 100% в лямбде

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;
   });
}
6 голосов
/ 01 декабря 2009

Вам действительно нужны перечисления? Я не думаю, что инкапсуляция вашей логики поиска в методе намного более понятна или более СУХА, чем просто использование методов linq:

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

и т.д.

3 голосов
/ 01 декабря 2009

Чтобы заставить это работать в лямбда-выражении, выражение должно сформировать Comparison<T> подпись. Это заняло бы 2 экземпляра «Персона». Вы можете сделать это следующим образом:

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;
             });
}
2 голосов
/ 01 декабря 2009
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 }

}

...