Сортировка настраиваемого списка классов <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. Дата имеет формат: дд.ММ.гггг.

Я читал кое-что об 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); });
ahsteele
источник
98
Вы также можете написать то же самое с помощью лямбда-выражения:list.Sort((a,b) => a.date.CompareTo(b.date));
Xavier Poinas 02
2
@Xavier по какой-то причине я все еще всегда сначала перескакиваю на предикаты, хотя вы на 100% правы, что ваше лямбда-выражение выполнит свою работу и, вероятно, его легче читать / понимать.
ahsteele 02
как это или как вы могли бы постоянно разрывать отношения, используя лямбда-выражение? Что, если здесь 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

Перво-наперво, если свойство date хранит дату, сохраните ее с помощью 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»). Для получения дополнительной информации см. Здесь и здесь .

AJ.
источник
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()
SirDemon
источник
3

посмотрите перегруженный метод Sort класса List. Есть несколько способов к этому. один из них: ваш настраиваемый класс должен реализовать интерфейс IComparable, тогда вы можете использовать метод Sort класса List.

Арсений
источник
3

Спасибо за все быстрые ответы.

Это мое решение:

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

Спасибо

Оборотень
источник
2
YourVariable.Sort((a, b) => a.amount.CompareTo(b.amount));
sansalk
источник