Что лучше использовать для сортировки IComparer или IComparable?Можете сказать что из них лучше использовать и почему? Лично я сам не совсем понял что из них лучше.
В .NET
классов коллекций и массивы поддерживают сортировку,с помощью одного метода, который, как правило, называется Sort()
.Однако метод Sort()
по умолчанию работает только для наборов примитивных типов, как int
или string
.
Для сортировки наборов сложных объектов применяется интерфейс IComparable
:
public interface IComparable
{
int CompareTo(object o);
}
Метод CompareTo
на выходе возвращает целое число, которое может иметь одно из трех значений:
IComparable
имеет обобщенную версию IComparable<T>
.
IComparable<T>
, если определено для T
, позволяет сравнить текущий экземпляр с другим экземпляром того же типа.
IComparable<T>
сопоставим,а IComparer<T>
сравнитель.
Кроме интерфейса IComparable
платформа .NET также предоставляет интерфейс IComparer
:
interface IComparer
{
int Compare(object o1, object o2);
}
Метод Compare
предназначен для сравнения двух объектов o1 и o2
.
Он также возвращает три значения, в зависимости от результата сравнения:
Если первый объект больше второго,
IComparer
имеет обобщенную версию IComparer<T>
.
IComparer<T>
может быть полезна,когда вам требуется сортировка на основе пользовательского порядка,но не как общее правило.Например,в классе Person
в какой-то момент вам может потребоваться сортировка людей в зависимости от их возраста. В этом случае вы можете
public class Person
{
public int Age;
}
public class AgeComparer : IComparer<Person>
{
public int Compare(Person x, Person y)
{
return x.Age - y.Age;
}
}
Обычно вам нужно IComparable<T>
.В идеале вы можете иметь только один IComparable<T>
, тогда как несколько IComparer<T>
возможны на основе разных критериев.
Это зависит от того, какой реальный смысл ваших данных.
Если ваша структура данных имеет естественную операцию сравнения, то вы должны реализовать IComparable<T>
(причин использовать нетипизированный IComparable
практически нет), при этом сортировка будет работать как надо.
Например, для структуры данных Rational
, представляющей собой натуральную дробь, операция сравнения очевидна:
class Rational : IComparable<Rational>
{
public int Numerator { get; }
public int Denominator { get; }
public int CompareTo(Rational that)
{
var result = Math.Sign((this.Numerator * that.Denominator)
.CompareTo(this.Denominator * that.Numerator));
if (Math.Sign(this.Denominator) != Math.Sign(that.Denominator))
result = -result;
return result;
}
}
Тогда смысл сортировки понятен: вы сортируете ваши объекты в их естественном порядке.
Если же у ваших объектов нету естественного порядка, то вам нет смысла реализовывать IComparable<T>
.
Например, если у вас есть объект Human
, у него нет естественного порядка. Иногда вам может захотеться отсортировать коллекцию людей иногда по росту, иногда по фамилии, иногда по дате рождения. В этом случае для сортировки вы либо указываете, как вычислить «вес» каждого объекта (как в LINQ-шном OrderBy
), либо указываете, как сравнить два элемента (класс IComparer<T>
или просто лямбда-функция Comparison<T>
). Легче всего, наверное, через OrderBy
:
humans.OrderBy(h => h.Surname).ToList()
Чуть сложнее через Comparison<T>
:
humans.Sort((p, q) =>
{
var n1 = p.Surname;
var n2 = q.Surname;
return (n1 > n2) ? 1 :
(n1 < b2) ? -1 : 0;
});
или просто
humans.Sort((p, q) => p.Surname.CompareTo(q.Surname));
То же можно сделать и через реализацию интерфейса IComparer<T>
:
class SurnameComparer : IComparer<Human>
{
public int Compare(Human p, Human q)
{
return p.Surname.CompareTo(q.Surname);
}
}
var cmp = new SurnameComparer;
humans.Sort(cmp);
— но этот путь обычно самый длинный, и нужен не так часто: например, когда вам нужно повторное использование этого «сравнивателя».
Это два разных варианта одного и того же процесса.
Интерфейс IComparable
, позволяет объекту быть "сравниваемым" с другим, что позволяет методом сортировки сортировать коллекции объектов, не вдумываясь что это за объекты. Т.е. объект сам знает, какой у него "статус" к другим объектам. Например есть объект Email
с полем email
и Name
с полем name
, и есть единый список из Email и Name
. Emai
l сравнивает email.toString()
и o.toString()
а Name
соответсвенно с name
. В итоге, если есть ситуация отсортировать этот общий список, он сортируется правильно, в соответствии с сущностью объектов.
Интерфейс IComparer
позволяет реализовать собственный вариант сортировки, для конкретного случая, учитывая конкретную ситуацию, а не суть классов. Например, можно реализовать на базе этого интерфейса два варианта ByNameCompare
r и ByEmailComparer
. И применить их в зависимости от ситуации, к одной коллекции - в одном случай по имени, в другом - по емейлу.
Кофе для программистов: как напиток влияет на продуктивность кодеров?
Рекламные вывески: как привлечь внимание и увеличить продажи
Стратегії та тренди в SMM - Технології, що формують майбутнє сьогодні
Выделенный сервер, что это, для чего нужен и какие характеристики важны?
Современные решения для бизнеса: как облачные и виртуальные технологии меняют рынок
Есть множество значений которые изменяются со временемЕсли значение достигает определенного критического значения (у каждого оно свое),...
Вопрос: Есть 1 текстовый файл, в котором указаны пути файловВ списке нет разделителей типа ; или каких либо других