Sortuj listę klas niestandardowych <T>

112

Chciałbym posortować listę według datewłaściwości.

To jest moja klasa niestandardowa:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

namespace Test.Web
{
    public class cTag
    {
        public int id { get; set; }
        public int regnumber { get; set; }
        public string date { get; set; }
    }
}

To jest to, Listco chcę sortować:

List<cTag> Week = new List<cTag>();

Chcę posortować Listę według datewłaściwości klasy cTag. Data ma format: dd.MM.rrrr.

Czytałem coś o IComparableinterfejsie, ale nie wiem, jak go używać.

Werewolve
źródło

Odpowiedzi:

143

Jednym ze sposobów jest użycie pliku delegate

List<cTag> week = new List<cTag>();
// add some stuff to the list
// now sort
week.Sort(delegate(cTag c1, cTag c2) { return c1.date.CompareTo(c2.date); });
ahsteele
źródło
98
Możesz również napisać to samo za pomocą wyrażenia lambda:list.Sort((a,b) => a.date.CompareTo(b.date));
Xavier Poinas
2
@Xavier z jakiegoś powodu zawsze skaczę w myślach najpierw do predykatów, chociaż masz 100% racji, że twoje wyrażenie Lambda wykonałoby zadanie i prawdopodobnie jest łatwiejsze do odczytania / zrozumienia.
ahsteele
jak to lub jak byś mógł konsekwentnie zerwać remis za pomocą wyrażenia lambda? Co jeśli a.date == b.date tutaj? list.Sort ((a, b) => a.date.CompareTo (b.data)); Czy spowodowałoby to problemy podczas stronicowania siatek, a te dwie przypadkowo wypadłyby na różnych stronach?
TheEmirOfGroofunkistan
1
@TheEmirOfGroofunkistan, że wszystko zależy od tego, jak CompareTozostanie wdrożone. IComparableprzyznaje, że klasa będzie miała metodę, ale sposób, w jaki zrobi to porównanie, zależy od twórcy klasy. Nie jestem pewien, jak Date implementuje ICompare, ale często widziałem, jak programiści używają parametrów zamówienia, które były przekazywane do zerwania remisu, gdy wartości są równe. hth
ahsteele
51

Masz rację, że Twoja klasa cTag musi implementować IComparable<T>interfejs. Następnie możesz po prostu zadzwonić Sort()na swoją listę.

Aby zaimplementować IComparable<T>interfejs, musisz zaimplementować CompareTo(T other)metodę. Najłatwiej to zrobić, wywołując metodę CompareTo pola, które chcesz porównać, którym w Twoim przypadku jest data.

public class cTag:IComparable<cTag> {
    public int id { get; set; }
    public int regnumber { get; set; }
    public string date { get; set; }
    public int CompareTo(cTag other) {
        return date.CompareTo(other.date);
    }
}

Jednak to nie posortowałoby się dobrze, ponieważ użyłoby klasycznego sortowania na łańcuchach (ponieważ zadeklarowałeś datę jako ciąg). Myślę więc, że najlepszym rozwiązaniem byłoby przedefiniowanie klasy i zadeklarowanie daty nie jako ciągu, ale jako DateTime. Kod pozostałby prawie taki sam:

public class cTag:IComparable<cTag> {
    public int id { get; set; }
    public int regnumber { get; set; }
    public DateTime date { get; set; }
    public int CompareTo(cTag other) {
        return date.CompareTo(other.date);
    }
}

Jedyne, co musiałbyś zrobić przy tworzeniu instancji klasy, aby przekonwertować swój ciąg znaków zawierający datę na typ DateTime, ale można to łatwo zrobić np DateTime.Parse(String). Metodą.

Ondra C.
źródło
38

W tym przypadku możesz również posortować za pomocą LINQ:

week = week.OrderBy(w => DateTime.Parse(w.date)).ToList();
Jakimycz
źródło
12
List<cTag> week = new List<cTag>();
week.Sort((x, y) => 
    DateTime.ParseExact(x.date, "dd.MM.yyyy", CultureInfo.InvariantCulture).CompareTo(
    DateTime.ParseExact(y.date, "dd.MM.yyyy", CultureInfo.InvariantCulture))
);
Darin Dimitrov
źródło
9

Po pierwsze, jeśli właściwość date przechowuje datę, zapisz ją przy użyciu DateTime. Jeśli przeanalizujesz datę przez sortowanie, musisz przeanalizować ją dla każdego porównywanego elementu, nie jest to zbyt wydajne ...

Następnie możesz utworzyć IComparer:

public class TagComparer : IComparer<cTag>
{
    public int Compare(cTag first, cTag second)
    {
        if (first != null && second != null)
        {
            // We can compare both properties.
            return first.date.CompareTo(second.date);
        }

        if (first == null && second == null)
        {
            // We can't compare any properties, so they are essentially equal.
            return 0;
        }

        if (first != null)
        {
            // Only the first instance is not null, so prefer that.
            return -1;
        }

        // Only the second instance is not null, so prefer that.
        return 1;
    }
}

var list = new List<cTag>();
// populate list.

list.Sort(new TagComparer());

Możesz to zrobić nawet jako delegat:

list.Sort((first, second) =>
          {
              if (first != null && second != null)
                  return first.date.CompareTo(second.date);

              if (first == null && second == null)
                  return 0;

              if (first != null)
                  return -1;

              return 1;
          });
Matthew Abbott
źródło
6

Masz rację - musisz wdrożyć IComparable. Aby to zrobić, po prostu zadeklaruj swoją klasę:

public MyClass : IComparable
{
  int IComparable.CompareTo(object obj)
  {
  }
}

W CompareTo po prostu zaimplementujesz własny algorytm porównania (możesz użyć do tego obiektów DateTime, ale upewnij się, że najpierw sprawdzisz typ „obj”). Więcej informacji można znaleźć tutaj i tutaj .

AJ.
źródło
7
IComparable<T>prawdopodobnie byłby lepszym wyborem, ponieważ jest to zaznaczone zamiast IComparable: msdn.microsoft.com/en-us/library/b0zbh7b6.aspx
Richard Szalay
5

Możesz użyć linq:

var q = from tag in Week orderby Convert.ToDateTime(tag.date) select tag;
List<cTag> Sorted = q.ToList()
SirDemon
źródło
3

spójrz na przeciążoną metodę Sort klasy List. jest na to kilka sposobów. jeden z nich: Twoja niestandardowa klasa musi zaimplementować interfejs IComparable, a następnie możesz użyć metody Sort klasy List.

Arseny
źródło
3

Dzięki za wszystkie szybkie odpowiedzi.

To jest moje rozwiązanie:

Week.Sort(delegate(cTag c1, cTag c2) { return DateTime.Parse(c1.date).CompareTo(DateTime.Parse(c2.date)); });

Dzięki

Werewolve
źródło
2
YourVariable.Sort((a, b) => a.amount.CompareTo(b.amount));
sansalk
źródło