2009-08-19 21 views
16

mam tej klasy:Jak posortować listę obiektów według określonego pola w języku C#?

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

to mam listę StatInfo, ale nie jestem pewien, jak go uporządkować według polu daty. Czy powinienem użyć metody sortowania? Czy mogę tworzyć własne?

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

Jaki jest najlepszy sposób robienia tego bez konieczności pisania ton kodu (jeśli to możliwe)?

Dzięki

+0

Zaczekaj Jon Skeet, aby pokazać się. Jego C# in Depth: To, czego potrzebujesz do opanowania C# 2 i 3, ma dużą sekcję na ten temat. – hughdbrown

+0

Za późno! Zawsze jestem zaskoczony, gdy jedno z moich pytań na C# nie dostało odpowiedzi od Jona Skeeta :) – marcgg

+1

Tytuł jest błędny. mówi "tablica" –

Odpowiedz

48

Używanie LINQ:

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

Sortowanie oryginalną listę:

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

Dzięki, druga metoda zadziałała. Nie używam LINQ, więc nie mogę przetestować drugiego. – marcgg

3

użycie wyrażenia lambda do mapowania parę do porównania:

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

Dzięki za odpowiedź, ale pojawia się błąd: Nie można przekonwertować wyrażenia lambda na typ System.Collections.Generic.IComparer ', ponieważ nie jest to typ delegata – marcgg

+0

Potrzebujesz co najmniej C# 3.0 (Visual Studio 2008/dowolna edycja). –

1

Dla DateTim e nie powinno być potrzeby porównywania.

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

lub

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

Obie metody zwracają listę z powrotem, więc potrzebujesz _allStatInfo = _allStatInfo.OrderBy (d => d.date) .ToList(); – TruthStands

+0

Dzięki, ale Lista <> nie ma takich funkcji, jeśli się nie mylę. – marcgg

+0

Domyślam się, że to LINQ. Nie używam LINQ – marcgg

3

Aby zilustrować Robert C. Cartaino za odpowiedź:

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

nie najbardziej ogólne rozwiązanie, ale dobre, jeśli tylko będzie sortować według daty. I, jak powiedział Robert, wciąż możesz zawsze przesłonić sortowanie domyślne, przekazując parametr IComparer do metody sortowania.

+0

dzięki. Nie odnosi się to w rzeczywistości do mojej sytuacji, ponieważ będę sortował tylko według daty w tej konkretnej sytuacji, ale będę o tym pamiętał później: – marcgg

+0

@marcgg: Kod w mojej odpowiedzi powoduje sortowanie według daty domyślnego zachowania. Więc jeśli sortujesz według daty, myślę, że właśnie tego chcesz. –

11

widzę masz odpowiedź tak, ale ...

  1. można uniknąć tylko przez pewną brzydotę podział oświadczenie na dwie połówki:

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

    Możesz chcieć rozważyć właśnie dzwoni CompareTo bezpośrednio, za:

    Comparison<StatInfo> comparison = (x, y) => x.date.CompareTo(y.date); 
    _allStatInfo.Sort(comparison); 
    
  2. można by utworzyć IComparer<T> Implementacja przy użyciu mojej klasy ProjectionComparer - jest częścią MiscUtil, a na tę odpowiedź dołączono wersję bez komentarza u dołu . Można by wtedy napisać:

    _allStatInfo.Sort(ProjectionComparer<StatInfo>.Create(x => x.date)); 
    
  3. Nawet jeśli używasz .NET 2.0, można nadal korzystać z LINQ drodze LINQBridge.

Oto klasa ProjectionComparer wymagana dla drugiej odpowiedzi. Pierwsze dwie klasy są naprawdę tylko pomocnikami, aby pozwolić, aby ogólne wnioskowanie typu działało lepiej.

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

Czy mówisz, że mój kod jest brzydki? :-( –

+0

Och, dziękuję, właśnie kiedy mówiłem, że nie dostałem odpowiedzi od ciebie na pytanie C# :) Będę trzymać odpowiedź Bena zaakceptowana, ale przegłosowałem twoją i jestem pewien, że to będzie tuż poniżej – marcgg

+1

@Ben: Po prostu nie podoba mi się wiele nawiasów, jeśli mogę pomóc :) –

1

pracował dla mnie ُ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

Dzięki, tylko odpowiedź, która zadziałała dla mnie. – lama12345

Powiązane problemy