Сортування користувацького списку класів <T>


112

Я хотів би сортувати свій список із dateвластивістю.

Це мій спеціальний клас:

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; }
    }
}

Це те, Listщо я хочу сортувати:

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

Що я хочу зробити, це сортувати Список за dateвластивістю класу cTag. Дата іст у форматі: dd.MM.yyyy

Я читав щось про IComparableінтерфейс, але не знаю, як ним користуватися.

Відповіді:


143

Один із способів зробити це - за допомогою 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); });

98
Те ж саме можна написати і з list.Sort((a,b) => a.date.CompareTo(b.date));
лямбдаським

2
@Xavier чомусь мій розум все ще завжди перескакує на предикати, хоча ви на 100% вірні, що ваш вираз лямбда виконав цю роботу і, ймовірно, легше читати / розуміти.
ahsteele

як це, чи як би ви розірвали краватку послідовно, використовуючи лямбдаський вираз? Що робити, якщо a.date == b.date тут? list.Sort ((a, b) => a.date.CompareTo (b.date)); Чи це створить проблеми, коли підключення сіток і ці дві випадково потрапляють на різні сторінки?
TheEmirOfGroofunkistan

1
@ TheEmirOfGroofunkistan, все залежить від того, як CompareToце буде реалізовано. IComparableхто отримав метод, але як це зробити, порівняння залежить від творця класу. Не впевнений, як Date реалізує ICompare, але часто я бачив, як розробники використовують параметри замовлення, щоб перервати краватку, коли значення рівні. hth
ahsteele

51

Ви вірні, що ваш клас cTag повинен реалізувати IComparable<T>інтерфейс. Тоді ви можете просто зателефонувати Sort()у свій список.

Для реалізації IComparable<T>інтерфейсу необхідно реалізувати CompareTo(T other)метод. Найпростіший спосіб зробити це - викликати метод CompareTo поля, яке ви хочете порівняти, який у вашому випадку є датою.

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

Однак це не вдасться впорядкувати, оскільки це використовує класичне сортування за рядками (оскільки ви оголосили дату як рядок). Тому я думаю, що найкраще подумати - це перезначити клас та оголосити дату не як рядок, а як DateTime. Код залишиться майже таким же:

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

Єдине, що вам доведеться зробити, створюючи екземпляр класу, щоб перетворити рядок, що містить дату, у тип DateTime, але це можна зробити легко, наприклад, DateTime.Parse(String)методом.


38

У цьому випадку ви також можете сортувати за допомогою LINQ:

week = week.OrderBy(w => DateTime.Parse(w.date)).ToList();

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

9

Спочатку спочатку, якщо властивість дати зберігає дату, зберігайте її за допомогою DateTime. Якщо ви аналізуєте дату за допомогою сортування, ви повинні проаналізувати її для кожного елемента, який порівнюється, це не дуже ефективно ...

Потім ви можете зробити 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());

Ви навіть можете це зробити як делегат:

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

6

Ви праві - вам потрібно реалізувати IComparable. Для цього просто оголосіть свій клас:

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

У CompareTo ви просто реалізуєте власний алгоритм порівняння (для цього ви можете використовувати об’єкти DateTime, але будьте впевнені, щоб спочатку перевірити тип "obj"). Додаткову інформацію дивіться тут і тут .


7
IComparable<T>Можливо, буде кращим вибором, оскільки він перевіряється на перевагу IComparable: msdn.microsoft.com/en-us/library/b0zbh7b6.aspx
Річард Салай

5

Ви можете використовувати linq:

var q = from tag in Week orderby Convert.ToDateTime(tag.date) select tag;
List<cTag> Sorted = q.ToList()

3

подивіться на перевантажений метод сортування класу List. Є кілька шляхів до цього. один з них: ваш користувальницький клас повинен реалізувати інтерфейс IComparable, тоді ви використовуєте метод сортування класу List.


3

Дякую за всі швидкі відповіді.

Це моє рішення:

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

Дякую


Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.