2009-08-19 8 views
16

J'ai cette classe:Comment trier une liste d'objets par un champ spécifique en C#?

public class StatInfo 
{ 
    public string contact; 
    public DateTime date; 
    public string action; 
} 

alors j'ai une liste de StatInfo, mais je ne suis pas sûr de savoir comment faire le tri selon le champ de date. Dois-je utiliser la méthode de tri? Devrais-je créer le mien? Quelle est la meilleure façon de le faire sans avoir à écrire des tonnes de code (si possible)?

Merci

+0

Attendez que Jon Skeet apparaisse. Son C# en profondeur: Ce que vous avez besoin de maîtriser C# 2 et 3 a une grande section sur cela. – hughdbrown

+0

Trop tard! Je suis toujours surpris quand une de mes questions sur C# n'obtient pas de réponse de Jon Skeet :) – marcgg

+1

le titre est faux. dit "array" –

Répondre

48

LINQ:

var sortedList = _allStatInfo.OrderBy(si => si.date).ToList(); 

Tri de la liste originale:

_allStatInfo.Sort(new Comparison<StatInfo>((x, y) => DateTime.Compare(x.date, y.date))); 
+0

Merci, la deuxième méthode a fonctionné. Je n'utilise pas LINQ, donc je ne peux pas tester le second. – marcgg

3

Utilisez une expression lambda pour mapper une paire à une comparaison:

_allStatInfo.Sort((x, y) => x.date - y.date); 
+0

Merci pour la réponse mais j'ai une erreur: Impossible de convertir l'expression lambda en type System.Collections.Generic.IComparer 'car ce n'est pas un type de délégué – marcgg

+0

Vous avez besoin d'au moins C# 3.0 (Visual Studio 2008/toute édition). –

1

Pour un DateTim Il ne devrait pas être nécessaire de comparer.

_allStatInfo.OrderyBy(d => d.date); 

ou

_allStatInfo.OrderByDescending(d => d.Date); 
+0

Les deux méthodes renvoient la liste, vous aurez donc besoin de _allStatInfo = _allStatInfo.OrderBy (d => d.date) .ToList(); – TruthStands

+0

Merci, mais une liste <> n'a pas de telles fonctions si je ne me trompe pas – marcgg

+0

Je suppose que c'est LINQ. Je n'utilise pas LINQ – marcgg

3

Pour illustrer la réponse de Robert C. Cartaino:

public class StatInfo : IComparable<StatInfo> 
{ 
    public string contact; 
    public DateTime date; 
    public string action; 

    public int CompareTo(StatInfo value) 
    { 
     return this.date.CompareTo(value.date); 
    } 
} 

var _allStatInfo = new List<StatInfo>(); 

// this now sorts by date 
_allStatInfo.Sort(); 

pas la solution la plus générale, mais bien si vous allez seulement trier par date. Et, comme Robert l'a dit, vous pouvez toujours remplacer le tri par défaut en passant un paramètre IComparer à la méthode de tri.

+0

merci. Cela ne s'applique pas vraiment à ma situation puisque je vais seulement trier par date dans cette situation particulière, mais je garderai cela à l'esprit pour plus tard – marcgg

+0

@marcgg: Le code dans ma réponse fait trier par date le comportement par défaut. Donc, si vous ne faites que trier par date, je pense que c'est exactement ce que vous voulez. –

11

Je vois que vous avez la réponse de toute façon, mais ...

  1. Vous pouvez éviter une laideur en divisant simplement la déclaration en deux moitiés:

    Comparison<StatInfo> comparison = (x, y) => DateTime.Compare(x.date, y.date); 
    _allStatInfo.Sort(comparison); 
    

    Vous pouvez considérer simplement appeler CompareTo directement aussi:

    Comparison<StatInfo> comparison = (x, y) => x.date.CompareTo(y.date); 
    _allStatInfo.Sort(comparison); 
    
  2. Vous pouvez créer un IComparer<T> mise en œuvre en utilisant ma ProjectionComparer classe - il fait partie de MiscUtil, et je l'ai inclus une version décommentée au bas de cette réponse. Vous auriez alors écrire:

    _allStatInfo.Sort(ProjectionComparer<StatInfo>.Create(x => x.date)); 
    
  3. Même si vous utilisez .NET 2.0, vous pouvez toujours utiliser LINQ par voie de LINQBridge.

est ici la classe ProjectionComparer requise pour la deuxième réponse. Les premières classes ne sont vraiment que des aides pour que l'inférence de type générique fonctionne mieux.

public static class ProjectionComparer 
{ 
    public static ProjectionComparer<TSource, TKey> Create<TSource, TKey> 
     (Func<TSource, TKey> projection) 
    { 
     return new ProjectionComparer<TSource, TKey>(projection); 
    } 

    public static ProjectionComparer<TSource, TKey> Create<TSource, TKey> 
     (TSource ignored, Func<TSource, TKey> projection) 
    { 
     return new ProjectionComparer<TSource, TKey>(projection); 
    } 

} 

public static class ProjectionComparer<TSource> 
{ 
    public static ProjectionComparer<TSource, TKey> Create<TKey> 
     (Func<TSource, TKey> projection) 
    { 
     return new ProjectionComparer<TSource, TKey>(projection); 
    } 
} 

public class ProjectionComparer<TSource, TKey> : IComparer<TSource> 
{ 
    readonly Func<TSource, TKey> projection; 
    readonly IComparer<TKey> comparer; 

    public ProjectionComparer(Func<TSource, TKey> projection) 
     : this (projection, null) 
    { 
    } 

    public ProjectionComparer(Func<TSource, TKey> projection, 
           IComparer<TKey> comparer) 
    { 
     projection.ThrowIfNull("projection"); 
     this.comparer = comparer ?? Comparer<TKey>.Default; 
     this.projection = projection; 
    } 

    public int Compare(TSource x, TSource y) 
    { 
     // Don't want to project from nullity 
     if (x==null && y==null) 
     { 
      return 0; 
     } 
     if (x==null) 
     { 
      return -1; 
     } 
     if (y==null) 
     { 
      return 1; 
     } 
     return comparer.Compare(projection(x), projection(y)); 
    } 
} 
+1

Voulez-vous dire que mon code est moche? :-( –

+0

Oh merci, juste quand je disais que je n'ai pas eu de réponse de votre part sur une question C# :) Je garderai la réponse de Ben acceptée mais j'ai upvoted la vôtre et je suis sûr que ce sera juste en dessous de – marcgg

+1

@Ben: Je n'aime pas beaucoup de parenthèses si je peux l'aider :) –

1

cela a fonctionné pour moi ُSorting array of custom type using delegate

// sort array by name 
Array.Sort(users, delegate(User user1, User user2) 
      { 
      return user1.Name.CompareTo(user2.Name); 
      }); 
// write array (output: Betty23 Lisa25 Susan20) 
foreach (User user in users) Console.Write(user.Name + user.Age + " "); 
+0

Merci, seule réponse qui a fonctionné pour moi. – lama12345

Questions connexes