2009-01-12 6 views

Répondre

14

Eh bien, puisque vous utilisez List<T> il serait beaucoup plus simple d'utiliser un Comparison<T>, par exemple:

List<Foo> data = ... 
// sort by name descending 
data.Sort((x,y) => -x.Name.CompareTo(y.Name)); 

Bien sûr, avec LINQ vous pouvez simplement utiliser:

var ordered = data.OrderByDescending(x=>x.Name); 

Mais vous pouvez ré-introduire dans d'List<T> (pour en place réordonnancement) assez facilement; Voici un exemple qui permet Sort sur List<T> avec la syntaxe lambda:

using System; 
using System.Collections.Generic; 

class Foo { // formatted for vertical space 
    public string Bar{get;set;} 
} 
static class Program { 
    static void Main() { 
     List<Foo> data = new List<Foo> { 
      new Foo {Bar = "abc"}, new Foo {Bar = "jkl"}, 
      new Foo {Bar = "def"}, new Foo {Bar = "ghi"} 
     }; 
     data.SortDescending(x => x.Bar); 
     foreach (var row in data) { 
      Console.WriteLine(row.Bar); 
     } 
    } 

    static void Sort<TSource, TValue>(this List<TSource> source, 
      Func<TSource, TValue> selector) { 
     var comparer = Comparer<TValue>.Default; 
     source.Sort((x,y)=>comparer.Compare(selector(x),selector(y))); 
    } 
    static void SortDescending<TSource, TValue>(this List<TSource> source, 
      Func<TSource, TValue> selector) { 
     var comparer = Comparer<TValue>.Default; 
     source.Sort((x,y)=>comparer.Compare(selector(y),selector(x))); 
    } 
} 
+0

Votre réponse commence un peu confuse, il suppose que j'ai déjà lu des informations qui ne sont pas dans la question mais dans une réponse postée par l'OP. – Stijn

9

Voici un exemple simple: «C'est super, mais si je veux être en mesure de contrôler l'ordre de tri, ou trier par un autre champ »

public class SortableItem : IComparable<SortableItem> 
{ 
    public int someNumber; 

    #region IComparable<SortableItem> Members 

    public int CompareTo(SortableItem other) 
    { 
     int ret = -1; 
     if (someNumber < other.someNumber) 
      ret = -1; 
     else if (someNumber > other.someNumber) 
      ret = 1; 
     else if (someNumber == other.someNumber) 
      ret = 0; 
     return ret; 
    } 

    #endregion 
} 

Simple. Tout ce que nous devons faire est d'ajouter quelques champs supplémentaires à l'objet. Nous allons d'abord ajouter une chaîne pour un type de tri différent, puis nous ajouterons un booléen pour indiquer si nous effectuons un tri par ordre décroissant ou croissant, puis ajouterons un champ qui détermine le champ que nous voulons rechercher.

public class SortableItem : IComparable<SortableItem> 
{ 
    public enum SortFieldType { SortNumber, SortString } 

    public int someNumber = -1; 
    public string someString = ""; 
    public bool descending = true;  
    public SortFieldType sortField = SortableItem.SortFieldType.SortNumber;   

    #region IComparable<SortableItem> Members 

    public int CompareTo(SortableItem other) 
    { 
     int ret = -1; 
     if(sortField == SortableItem.SortFieldType.SortString) 
     { 
      // A lot of other objects implement IComparable as well. 
      // Take advantage of this. 
      ret = someString.CompareTo(other.someString); 
     } 
     else 
     { 
      if (someNumber < other.someNumber) 
       ret = -1; 
      else if (someNumber > other.someNumber) 
       ret = 1; 
      else if (someNumber == other.someNumber) 
       ret = 0; 
     } 
     // A quick way to switch sort order: 
     // -1 becomes 1, 1 becomes -1, 0 stays the same. 
     if(!descending) ret = ret * -1; 

     return ret; 
    } 

    #endregion 

    public override string ToString() 
    { 
     if(sortField == SortableItem.SortFieldType.SortString) 
      return someString; 
     else 
      return someNumber.ToString(); 
    } 
} 

"Montrez-moi comment!"

Eh bien puisque vous avez demandé si bien.

static class Program 
{ 
    static void Main() 
    { 

     List<SortableItem> items = new List<SortableItem>(); 
     SortableItem temp = new SortableItem(); 
     temp.someString = "Hello"; 
     temp.someNumber = 1; 
     items.Add(temp); 
     temp = new SortableItem(); 
     temp.someString = "World"; 
     temp.someNumber = 2; 
     items.Add(temp); 
     SortByString(items); 
     Output(items); 
     SortAscending(items); 
     Output(items); 
     SortByNumber(items); 
     Output(items); 
     SortDescending(items); 
     Output(items); 
     Console.ReadKey(); 
    } 

    public static void SortDescending(List<SortableItem> items) 
    { 
     foreach (SortableItem item in items) 
      item.descending = true; 
    } 
    public static void SortAscending(List<SortableItem> items) 
    { 
     foreach (SortableItem item in items) 
      item.descending = false; 
    } 
    public static void SortByNumber(List<SortableItem> items) 
    { 
     foreach (SortableItem item in items) 
      item.sortField = SortableItem.SortFieldType.SortNumber; 
    } 
    public static void SortByString(List<SortableItem> items) 
    { 
     foreach (SortableItem item in items) 
      item.sortField = SortableItem.SortFieldType.SortString; 
    } 
    public static void Output(List<SortableItem> items) 
    { 
     items.Sort(); 
     for (int i = 0; i < items.Count; i++) 
      Console.WriteLine("Item " + i + ": " + items[i].ToString()); 
    } 
} 
+0

qui est en fait assez yeucky, désolé de le dire. Il y a de bien meilleures approches, en particulier en utilisant LINQ ou une approche inspirée par LINQ ... –

+5

Il n'y a rien qui dise que vous ne pouvez pas répondre à la question aussi si vous avez une meilleure idée. –

+0

J'ai - je l'écris juste ;-p –

4

Si vous voulez genre dynamique, vous pouvez utiliser LINQ

var itemsOrderedByNumber = (from item in GetClasses() orderby item.Number select item).ToList(); 
var itemsOrderedByText = (from item in GetClasses() orderby item.Text select item).ToList(); 
var itemsOrderedByDate = (from item in GetClasses() orderby item.Date select item).ToList(); 

ou "Trier" méthode de la liste des classes:

List<Class1> itemsOrderedByNumber2 = new List<Class1>(GetClasses()); 
itemsOrderedByNumber2.Sort((a, b) => Comparer<int>.Default.Compare(a.Number, b.Number)); 

List<Class1> itemsOrderedByText2 = new List<Class1>(GetClasses()); 
itemsOrderedByText2.Sort((a, b) => Comparer<string>.Default.Compare(a.Text, b.Text)); 

List<Class1> itemsOrderedByDate2 = new List<Class1>(GetClasses()); 
itemsOrderedByDate2.Sort((a, b) => Comparer<DateTime>.Default.Compare(a.Date, b.Date)); 
0

Cela pourrait ne pas être en relation avec l'ordre de tri, mais il est encore - je pense - une utilisation intéressante de IComparable:

public static void MustBeInRange<T>(this T x, T minimum, T maximum, string paramName) 
where T : IComparable<T> 
{ 
    bool underMinimum = (x.CompareTo(minimum) < 0); 
    bool overMaximum = (x.CompareTo(maximum) > 0); 
    if (underMinimum || overMaximum) 
    { 
     string message = string.Format(
      System.Globalization.CultureInfo.InvariantCulture, 
      "Value outside of [{0},{1}] not allowed/expected", 
      minimum, maximum 
     ); 
     if (string.IsNullOrEmpty(paramName)) 
     { 
      Exception noInner = null; 
      throw new ArgumentOutOfRangeException(message, noInner); 
     } 
     else 
     { 
      throw new ArgumentOutOfRangeException(paramName, x, message); 
     } 
    } 
} 

public static void MustBeInRange<T>(this T x, T minimum, T maximum) 
where T : IComparable<T> { x.MustBeInRange(minimum, maximum, null); } 

ces méthodes simples d'extension vous permettent d'effectuer la vérification de la plage de paramètres pour tout type qui implémente IComparable comme ceci:

public void SomeMethod(int percentage, string file) { 
    percentage.MustBeInRange(0, 100, "percentage"); 
    file.MustBeInRange("file000", "file999", "file"); 
    // do something with percentage and file 
    // (caller will have gotten ArgumentOutOfRangeExceptions when applicable) 
} 
+0

Pour être honnête, il est peu probable que vous l'utilisiez sur un type qui n'est pas 'IComparable ' ou 'IComparable', donc je laisserais tomber la contrainte et utiliser Comparer .Default. C'est, par exemple, comment LINQ-to-Objects fait Min/Max. –

+0

N'avait pas bien de cela. Merci pour le conseil. Cependant, cela ne montrerait-il pas tout à la méthode d'extension (= sur les types je serais "peu susceptible de l'utiliser sur") alors qu'avec la contrainte de type elle ne montrera que sur les types qui sont réellement IComparable? – peSHIr

0
using System; 
using System.Collections.Generic; 
using System.Text; 

namespace Sorting_ComplexTypes 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      Customer customer1 = new Customer { 
       ID = 101, 
       Name = "Mark", 
       Salary = 2400, 
       Type = "Retail Customers" 
      }; 
      Customer customer2 = new Customer 
      { 
       ID = 102, 
       Name = "Brian", 
       Salary = 5000, 
       Type = "Retail Customers" 
      }; 
      Customer customer3 = new Customer 
      { 
       ID = 103, 
       Name = "Steve", 
       Salary = 3400, 
       Type = "Retail Customers" 
      }; 

      List<Customer> customer = new List<Customer>(); 
      customer.Add(customer1); 
      customer.Add(customer2); 
      customer.Add(customer3); 

      Console.WriteLine("Before Sorting"); 
      foreach(Customer c in customer) 
      { 
       Console.WriteLine(c.Name); 
      } 

      customer.Sort(); 
      Console.WriteLine("After Sorting"); 
      foreach(Customer c in customer) 
      { 
       Console.WriteLine(c.Name); 
      } 

      customer.Reverse(); 
      Console.WriteLine("Reverse Sorting"); 
      foreach (Customer c in customer) 
      { 
       Console.WriteLine(c.Name); 
      } 
      } 
     } 
    } 
    public class Customer : IComparable<Customer> 
    { 
     public int ID { get; set; } 
     public string Name { get; set; } 
     public int Salary { get; set; } 
     public string Type { get; set; } 

     public int CompareTo(Customer other) 
     { 
      return this.Name.CompareTo(other.Name); 
     } 
    } 
1

Vous pouvez l'utiliser pour la liste de tri

namespace GenaricClass 
{ 
    class Employee :IComparable<Employee> 
    { 
     public string Name { get; set; } 
     public double Salary { get; set; } 

     public int CompareTo(Employee other) 
     { 
      if (this.Salary < other.Salary) return 1; 
      else if (this.Salary > other.Salary) return -1; 
      else return 0; 
     } 

     public static void Main() 
     { 
      List<Employee> empList = new List<Employee>() 
      { 
       new Employee{Name="a",Salary=140000}, 
       new Employee{Name="b",Salary=120000}, 
       new Employee{Name="c",Salary=160000}, 
       new Employee{Name="d",Salary=10000} 
      }; 
      empList.Sort(); 
      foreach (Employee emp in empList) 
      { 
       System.Console.Write(emp.Salary +","); 
      } 
      System.Console.ReadKey(); 
     } 
    } 
}