2009-08-19 8 views
16

Ho questa classe:Come ordinare un elenco di oggetti per un campo specifico in C#?

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

poi ho un elenco di StatInfo, ma non sono sicuro di come ordinare secondo il campo della data. Dovrei usare il metodo sort? Dovrei creare il mio?

var _allStatInfo = new List<StatInfo>(); 
// adding lots of stuff in it 
_allStatInfo.SortByDate??? 

Qual è il modo migliore per farlo senza dover scrivere tonnellate di codice (se possibile)?

Grazie

+0

Attendere che Jon Skeet di presentarsi. Il suo C# in profondità: Ciò di cui hai bisogno per padroneggiare C# 2 e 3 ha una grande sezione proprio su questo. – hughdbrown

+0

Troppo tardi! Sono sempre sorpreso quando una delle mie domande su C# non riceve risposta da Jon Skeet :) – marcgg

+1

titolo errato. dice "array" –

risposta

48

utilizzando LINQ:

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

Ordinamento della lista originale:

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

Grazie, il secondo metodo ha funzionato. Non uso LINQ, quindi non posso testare il secondo. – marcgg

3

usare un'espressione lambda per mappare una coppia ad un confronto:

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

Grazie per la risposta, ma ottengo un errore: Impossibile convertire espressione lambda per digitare System.Collections.Generic.IComparer 'perché non è un tipo delegato – marcgg

+0

È necessario almeno C# 3.0 (Visual Studio 2008/qualsiasi edizione). –

1

Per un DateTim e non ci dovrebbe essere la necessità di confrontare.

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

o

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

Entrambi i metodi restituiscono l'elenco, quindi è necessario _allStatInfo = _allStatInfo.OrderBy (d => d.date) .ToList(); – TruthStands

+0

Grazie, ma un elenco <> non ha tali funzioni se non sto sbagliando – marcgg

+0

Immagino che questo sia LINQ. Non sto usando LINQ – marcgg

3

Per illustrare la risposta di 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(); 

Non è la soluzione più generale, ma buono se si sta solo andando a ordinare per data. E, come ha detto Robert, è sempre possibile sovrascrivere l'ordinamento predefinito passando un parametro IComparer al metodo di ordinamento.

+0

grazie. Non si applica realmente alla mia situazione poiché selezionerò solo per data in questa particolare situazione, ma terrò questo a mente per più tardi – marcgg

+0

@marcgg: Il codice nella mia risposta rende ordinamento per data il comportamento predefinito. Quindi, se stai ordinando solo per data, penso che sia esattamente quello che vuoi. –

11

Vedo che hai la risposta in ogni caso, ma ...

  1. È possibile evitare alcune brutture semplicemente dividendo la dichiarazione in due parti:

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

    Si potrebbe desiderare di prendere in considerazione solo chiamando CompareTo direttamente anche:

    Comparison<StatInfo> comparison = (x, y) => x.date.CompareTo(y.date); 
    _allStatInfo.Sort(comparison); 
    
  2. è possibile creare unImplementazioneutilizzando la mia classe ProjectionComparer - fa parte di MiscUtil e ho incluso una versione senza commento nella parte inferiore di questa risposta. Farebbe quindi scrivete:

    _allStatInfo.Sort(ProjectionComparer<StatInfo>.Create(x => x.date)); 
    
  3. Anche se si sta utilizzando .NET 2.0, è comunque possibile utilizzare LINQ per mezzo di LINQBridge.

Ecco la classe ProjectionComparer richiesta per la seconda risposta. Il primo paio di classi sono in realtà solo aiutanti per far sì che l'inferenza di tipo generico funzioni meglio.

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

Stai dicendo che il mio codice è brutto? :-( –

+0

Oh grazie, proprio mentre stavo dicendo che non ho ricevuto risposta da te in una domanda C# :) Terrò la risposta di Ben accettata ma ho svalutato la tua e sono sicuro che sarà proprio sotto – marcgg

+1

@ Ben: Non mi piacciono le tante parentesi se posso aiutarlo :) –

1

ha funzionato per me ُ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

Grazie, unica risposta che ha funzionato per me. – lama12345

Problemi correlati