Compareto c как работает
Большинство встроенных в .NET классов коллекций и массивы поддерживают сортировку. С помощью одного метода, который, как правило, называется Sort() можно сразу отсортировать по возрастанию весь набор данных. Например:
int[] numbers = new int[] < 97, 45, 32, 65, 83, 23, 15 >; Array.Sort(numbers); foreach (int n in numbers) Console.WriteLine(n); // 15 23 32 45 65 83 97
Однако метод Sort по умолчанию работает только для наборов примитивных типов, как int или string. Для сортировки наборов сложных объектов применяется интерфейс IComparable . Он имеет всего один метод:
public interface IComparable
Метод CompareTo предназначен для сравнения текущего объекта с объектом, который передается в качестве параметра object? o . На выходе он возвращает целое число, которое может иметь одно из трех значений:
- Меньше нуля. Значит, текущий объект должен находиться перед объектом, который передается в качестве параметра
- Равен нулю. Значит, оба объекта равны
- Больше нуля. Значит, текущий объект должен находиться после объекта, передаваемого в качестве параметра
Например, имеется класс Person:
class Person : IComparable < public string Name < get;>public int Age < get; set; >public Person(string name, int age) < Name = name; Age = age; >public int CompareTo(object? o) < if(o is Person person) return Name.CompareTo(person.Name); else throw new ArgumentException("Некорректное значение параметра"); >>
Здесь в качестве критерия сравнения выбрано свойство Name объекта Person. Поэтому при сравнении здесь фактически идет сравнение значения свойства Name текущего объекта и свойства Name объекта, переданного через параметр. Если вдруг объект не удастся привести к типу Person, то выбрасывается исключение.
var tom = new Person("Tom", 37); var bob = new Person("Bob", 41); var sam = new Person("Sam", 25); Person[] people = < tom, bob, sam>; Array.Sort(people); foreach (Person person in people) < Console.WriteLine($"- "); >
И в данном случае мы получим следующий консольный вывод:
Bob - 41 Sam - 25 Tom - 37
Интерфейс IComparable имеет обобщенную версию, поэтому мы могли бы сократить и упростить его применение в классе Person:
class Person : IComparable < public string Name < get;>public int Age < get; set; >public Person(string name, int age) < Name = name; Age = age; >public int CompareTo(Person? person) < if(person is null) throw new ArgumentException("Некорректное значение параметра"); return Name.CompareTo(person.Name); >>
Аналогичным образом мы можем сравнивать по возрасту:
class Person : IComparable < public string Name < get;>public int Age < get; set; >public Person(string name, int age) < Name = name; Age = age; >public int CompareTo(Person? person) < if(person is null) throw new ArgumentException("Некорректное значение параметра"); return Age - person.Age; >>
Применение компаратора
Кроме интерфейса IComparable платформа .NET также предоставляет интерфейс IComparer:
public interface IComparer
Метод Compare предназначен для сравнения двух объектов o1 и o2. Он также возвращает три значения, в зависимости от результата сравнения: если первый объект больше второго, то возвращается число больше 0, если меньше — то число меньше нуля; если оба объекта равны, возвращается ноль.
Создадим компаратор объектов Person. Пусть он сравнивает объекты в зависимости от длины строки — значения свойства Name:
class PeopleComparer : IComparer < public int Compare(Person? p1, Person? p2) < if(p1 is null || p2 is null) throw new ArgumentException("Некорректное значение параметра"); return p1.Name.Length - p2.Name.Length; >> class Person < public string Name < get;>public int Age < get; set; >public Person(string name, int age) < Name = name; Age = age; >>
В данном случае используется обобщенная версия интерфейса IComparer, чтобы не делать излишних преобразований типов. Применение компаратора:
var alice = new Person("Alice", 41); var tom = new Person("Tom", 37); var kate = new Person("Kate", 25); Person[] people = < alice, tom, kate>; Array.Sort(people, new PeopleComparer()); foreach (Person person in people) < Console.WriteLine($"- "); >
Объект компаратора указывается в качестве второго параметра метода Array.Sort() . При этом не важно, реализует ли класс Person интерфейс IComparable или нет. Правила сортировки, установленные компаратором, будут иметь больший приоритет. В начале будут идти объекты Person, у которых имена меньше, а в конце — у которых имена длиннее:
Tom - 37 Kate - 25 Alice - 41
Использование интерфейсов IComparable и интерфейсов IComparer в Visual CSharp
В этой статье описывается использование интерфейсов IComparer IComparable и интерфейсов в Visual C#.
Исходная версия продукта: Visual C #
Исходный номер базы знаний: 320727
Аннотация
Интерфейсы IComparable IComparer и интерфейсы рассматриваются в одной статье по двум причинам. Эти интерфейсы часто используются вместе. Хотя интерфейсы похожи и имеют похожие имена, они служат для разных целей.
Если у вас есть массив типов (например, строка или целое число), IComparer которые уже поддерживаются, можно отсортировать этот массив без явной ссылки IComparer на . В этом случае элементы массива IComparer приведения к реализации по умолчанию ( Comparer.Default ) для вас. Однако если вы хотите предоставить возможность сортировки или сравнения для пользовательских объектов, необходимо реализовать любой из этих интерфейсов или оба этих интерфейса.
Эта статья ссылается на пространство имен платформа .NET Framework классов Майкрософт System.Collections .
IComparable
Роль — IComparable предоставить метод сравнения двух объектов определенного типа. Это необходимо, если вы хотите предоставить возможность упорядочивания для объекта. Представьте, IComparable что вы предоставляете порядок сортировки по умолчанию для объектов. Например, если у вас есть массив объектов вашего типа и Sort вы вызываете метод для этого массива, IComparable обеспечивается сравнение объектов во время сортировки. При реализации интерфейса IComparable необходимо реализовать CompareTo метод следующим образом:
// Implement IComparable CompareTo method - provide default sort order. int IComparable.CompareTo(object obj)
Сравнение в методе отличается в зависимости от типа данных сравниваемого значения. String.Compare используется в этом примере, так как свойство, выбранное для сравнения, является строкой.
IComparer
Роль этой функции IComparer — предоставить дополнительные механизмы сравнения. Например, может потребоваться упорядочение класса по нескольким полям или свойствам, по возрастанию и убыванию для одного и того же поля или обоих.
Использование IComparer — это двухфакторный процесс. Сначала объявите класс, который реализует IComparer , а затем реализуйте Compare метод:
private class SortYearAscendingHelper : IComparer < int IComparer.Compare(object a, object b) < Car c1=(Car)a; Car c2=(Car)b; if (c1.year >c2.year) return 1; if (c1.year < c2.year) return -1; else return 0; >>
Для IComparer.Compare этого метода требуется сравнение по методу. Возвращается значение 1, 0 или -1 в зависимости от того, больше, равно или меньше другого. Порядок сортировки (по возрастанию или убыванию) можно изменить, переключив логические операторы в этом методе.
Второй шаг — объявление метода, который возвращает экземпляр объекта IComparer :
public static IComparer SortYearAscending()
В этом примере объект используется в качестве второго аргумента при вызове перегруженного Array.Sort метода, который принимает. IComparer Использование не IComparer ограничивается массивами. Он принимается в качестве аргумента во многих различных классах коллекций и элементов управления.
Пошаговый пример
В следующем примере показано использование этих интерфейсов. Для демонстрации IComparer и IComparable создания класса с именем Car . Объект Car имеет свойства make и year. В интерфейсе включена сортировка по возрастанию для поля make IComparable , а в поле make — сортировка IComparer по убыванию. Сортировка по возрастанию и убыванию предоставляется для свойства года с помощью IComparer .
- В Visual C# создайте проект консольного приложения. Приведите имя consoleEnum приложения.
- Переименуйте Program.cs в Host.cs, а затем замените код приведенным ниже кодом.
using System; namespace ConsoleEnum < class host < [STAThread] static void Main(string[] args) < // Create an array of Car objects. Car[] arrayOfCars= new Car[6] < new Car("Ford",1992), new Car("Fiat",1988), new Car("Buick",1932), new Car("Ford",1932), new Car("Dodge",1999), new Car("Honda",1977) >; // Write out a header for the output. Console.WriteLine("Array - Unsorted\n"); foreach(Car c in arrayOfCars) Console.WriteLine(c.Make + "\t\t" + c.Year); // Demo IComparable by sorting array with "default" sort order. Array.Sort(arrayOfCars); Console.WriteLine("\nArray - Sorted by Make (Ascending - IComparable)\n"); foreach(Car c in arrayOfCars) Console.WriteLine(c.Make + "\t\t" + c.Year); // Demo ascending sort of numeric value with IComparer. Array.Sort(arrayOfCars,Car.SortYearAscending()); Console.WriteLine("\nArray - Sorted by Year (Ascending - IComparer)\n"); foreach(Car c in arrayOfCars) Console.WriteLine(c.Make + "\t\t" + c.Year); // Demo descending sort of string value with IComparer. Array.Sort(arrayOfCars,Car.SortMakeDescending()); Console.WriteLine("\nArray - Sorted by Make (Descending - IComparer)\n"); foreach(Car c in arrayOfCars) Console.WriteLine(c.Make + "\t\t" + c.Year); // Demo descending sort of numeric value using IComparer. Array.Sort(arrayOfCars,Car.SortYearDescending()); Console.WriteLine("\nArray - Sorted by Year (Descending - IComparer)\n"); foreach(Car c in arrayOfCars) Console.WriteLine(c.Make + "\t\t" + c.Year); Console.ReadLine(); > > >
using System; using System.Collections; namespace ConsoleEnum < public class Car : IComparable < // Beginning of nested classes. // Nested class to do ascending sort on year property. private class SortYearAscendingHelper: IComparer < int IComparer.Compare(object a, object b) < Car c1=(Car)a; Car c2=(Car)b; if (c1.year >c2.year) return 1; if (c1.year < c2.year) return -1; else return 0; >> // Nested class to do descending sort on year property. private class SortYearDescendingHelper: IComparer < int IComparer.Compare(object a, object b) < Car c1=(Car)a; Car c2=(Car)b; if (c1.year < c2.year) return 1; if (c1.year >c2.year) return -1; else return 0; > > // Nested class to do descending sort on make property. private class SortMakeDescendingHelper: IComparer < int IComparer.Compare(object a, object b) < Car c1=(Car)a; Car c2=(Car)b; return String.Compare(c2.make,c1.make); >> // End of nested classes. private int year; private string make; public Car(string Make,int Year) < make=Make; year=Year; >public int Year < get set > public string Make < get set > // Implement IComparable CompareTo to provide default sort order. int IComparable.CompareTo(object obj) < Car c=(Car)obj; return String.Compare(this.make,c.make); >// Method to return IComparer object for sort helper. public static IComparer SortYearAscending() < return (IComparer) new SortYearAscendingHelper(); >// Method to return IComparer object for sort helper. public static IComparer SortYearDescending() < return (IComparer) new SortYearDescendingHelper(); >// Method to return IComparer object for sort helper. public static IComparer SortMakeDescending() < return (IComparer) new SortMakeDescendingHelper(); >> >
Array - Unsorted Ford 1992 Fiat 1988 Buick 1932 Ford 1932 Dodge 1999 Honda 1977 Array - Sorted by Make (Ascending - IComparable) Buick 1932 Dodge 1999 Fiat 1988 Ford 1932 Ford 1992 Honda 1977 Array - Sorted by Year (Ascending - IComparer) Ford 1932 Buick 1932 Honda 1977 Fiat 1988 Ford 1992 Dodge 1999 Array - Sorted by Make (Descending - IComparer) Honda 1977 Ford 1932 Ford 1992 Fiat 1988 Dodge 1999 Buick 1932 Array - Sorted by Year (Descending - IComparer) Dodge 1999 Ford 1992 Fiat 1988 Honda 1977 Buick 1932 Ford 1932
Обратная связь
Были ли сведения на этой странице полезными?
Объясните как работает compare() в порядке возрастания и убывания
Почему если в методе compare() возвращать return aStr.compareTo(bStr); то коллекция будет сортироваться в порядке возрастания, а если return bStr.compareTo(aStr); , то в порядке убывания?
Отслеживать
задан 20 авг 2021 в 20:09
teoretik_eugene teoretik_eugene
59 4 4 бронзовых знака
1 ответ 1
Сортировка: Сброс на вариант по умолчанию
Потому что упрощено говоря aStr.compareTo(bStr) равно -bStr.compareTo(aStr). Т.е. если aStr.compareTo(bStr) возвращает 1, то bStr.compareTo(aStr) вернёт -1. Поэтому и сортировка производится в обратную сторону.
Пример на числах: допустим в функцию сравнения (не эту, но похожую) передается два числа a и b. Если функция возвращает 1, то мы первое число ставим перед вторым. Если же -1, то второе перед первым. В одном случае получится возрастающая сортировка, в другом убывающая.
Отслеживать
ответ дан 20 авг 2021 в 20:15
26.3k 7 7 золотых знаков 32 32 серебряных знака 48 48 бронзовых знаков
Т.е., если у нас значение будет >0, то сортировка будет производиться в порядке возрастания, если же < 0 - то наоборот?
20 авг 2021 в 20:28
Вообще не совсем так, но для простоты пусть будет так.
20 авг 2021 в 20:31
Метод compareTo() уже и сравнивает, какая из строк «больше». А как этот результат дальше применяется из этого кода не видно.
Реализация интерфейса IComparable

Если требуется отсортировать коллекцию, состоящую из объектов определяемого пользователем класса, при условии, что они не сохраняются в коллекции класса SortedList, где элементы располагаются в отсортированном порядке, то в такой коллекции должен быть известен способ сортировки содержащихся в ней объектов. С этой целью можно, в частности, реализовать интерфейс IComparable для объектов сохраняемого типа. Интерфейс IComparable доступен в двух формах: обобщенной и необобщенной. Несмотря на сходство применения обеих форм данного интерфейса, между ними имеются некоторые, хотя и небольшие, отличия.
Если требуется отсортировать объекты, хранящиеся в необобщенной коллекции, то для этой цели придется реализовать необобщенный вариант интерфейса IComparable. В этом варианте данного интерфейса определяется только один метод, CompareTo(), который определяет порядок выполнения самого сравнения. Ниже приведена общая форма объявления метода CompareTo():
int CompareTo(object obj)
В методе CompareTo() вызывающий объект сравнивается с объектом obj. Для сортировки объектов по нарастающей конкретная реализация данного метода должна возвращать нулевое значение, если значения сравниваемых объектов равны; положительное — если значение вызывающего объекта больше, чем у объекта obj; и отрицательное — если значение вызывающего объекта меньше, чем у объекта obj. А для сортировки по убывающей можно обратить результат сравнения объектов. Если же тип объекта obj не подходит для сравнения с вызывающим объектом, то в методе CompareTo() может быть сгенерировано исключение ArgumentException.
Если требуется отсортировать объекты, хранящиеся в обобщенной коллекции, то для этой цели придется реализовать обобщенный вариант интерфейса IComparable. В этом варианте интерфейса IComparable определяется приведенная ниже обобщенная форма метода CompareTo():
int CompareTo(Т other)
В методе CompareTo() вызывающий объект сравнивается с другим объектом other. Для сортировки объектов по нарастающей конкретная реализация данного метода должна возвращать нулевое значение, если значения сравниваемых объектов равны; положительное — если значение вызывающего объекта больше, чем у объекта другого other; и отрицательное — если значение вызывающего объекта меньше, чем у другого объекта other. А для сортировки по убывающей можно обратить результат сравнения объектов. При реализации обобщенного интерфейса IComparable имя типа реализующего класса обычно передается в качестве аргумента типа.
Давайте рассмотрим пример реализации интерфеса IComparable для сортировки базы данных автомагазина:
using System; using System.Collections.Generic; namespace ConsoleApplication1 < class AutoShop : IComparable < public string CarName < set; get; >public int MaxSpeed < get; set; >public double Cost < get; set; >public byte Discount < get; set; >public int ID < get; set; >public AutoShop() < >public AutoShop(string CarName, int MaxSpeed, double Cost, byte Discount, int ID) < this.CarName = CarName; this.MaxSpeed = MaxSpeed; this.Cost = Cost; this.Discount = Discount; this.ID = ID; >// Реализуем интерфейс IComparable public int CompareTo(AutoShop obj) < if (this.Cost >obj.Cost) return 1; if (this.Cost < obj.Cost) return -1; else return 0; >public override string ToString() < return String.Format("\tМарка: \tМакс. скорость: \tЦена: \tСкидка: %", this.CarName,this.MaxSpeed,this.Cost,this.Discount,this.ID); > > class Program < static void Main() < Listdic = new List(); // Создадим множество автомобилей dic.Add(new AutoShop("Toyota Corolla", 180, 300000, 5, 1)); dic.Add(new AutoShop("VAZ 2114i", 160, 220000, 0, 2)); dic.Add(new AutoShop("Daewoo Nexia", 140, 260000, 5, 3)); dic.Add(new AutoShop("Honda Torneo", 220, 400000, 7, 4)); dic.Add(new AutoShop("Audi R8 Best", 360, 4200000, 3, 5)); Console.WriteLine("Исходный каталог автомобилей: \n"); foreach (AutoShop a in dic) Console.WriteLine(a); Console.WriteLine("\nТеперь автомобили отсортированны по стоимости: \n"); dic.Sort(); foreach (AutoShop a in dic) Console.WriteLine(a); Console.ReadLine(); > > >