Форум программистов, компьютерный форум, киберфорум
C# для начинающих
Войти
Регистрация
Восстановить пароль
 
 
Рейтинг 5.00/9: Рейтинг темы: голосов - 9, средняя оценка - 5.00
802 / 352 / 29
Регистрация: 08.01.2017
Сообщений: 2,387
1

Метод сравнения объектов пользовательского класса

02.08.2020, 16:48. Просмотров 1712. Ответов 27
Метки нет (Все метки)

Нужно написать метод сравнения достаточно сложных объектов пользовательского класса - для сортировки массива этих объектов.
Вижу, что есть два интерфейса: IComparable и IComparer
А может и ещё что-то есть (не знаю).
Какой из них использовать?
P.S.1. Не знаю важно это или нет, но сообщаю - эти объекты с рекурсией, то бишь, содержат в себе вложенные объекты того же типа (точнее - массив таких объектов).
P.S.2. Можно, конечно, вообще никакие интерфейсы не притягивать, но захотелось сделать правильно - задача-то стандартная и значит вроде нужно обозначить использование стандартного интерфейса))) Какого?


Добавлено через 12 минут
P.S.3. А тут ваще не получится "зацикливания"?
Есть массив объектов.
Каждый элемент массива тоже содержит массив объектов этого типа (возможно и нулевой длины).
Чтобы отсортировать массив, нужно иметь метод сравнения элементов. Но чтобы сравнивать элементы массива - объекты - нужно ведь уметь сортировать массив объектов, вложенный в каждый элемент массива (объект) ???)))
0
Лучшие ответы (1)
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
02.08.2020, 16:48
Ответы с готовыми решениями:

Программа, использующая массив объектов пользовательского класса
Написать код программы, в которой реализовать следующие действия: - инициализировать массив из 5...

Во всех классах реализовать интерфейс IComparable и перегрузить метод CompareTo для сравнения объектов
В программах требуется описать базовый класс (возможно, абстрактный), в котором задается интерфейс...

Для массива объектов класса «Студент» создать метод сортировки по различным критериям
Для массива объектов класса «Студент» создать метод сортировки по различным критериям (по фамилии,...

Задать метод события для множества объектов одного класса
Здравствуйте! Вынужден обратиться к опытным людям за советом. Имеется форма, на которой есть 60...

27
1427 / 901 / 411
Регистрация: 14.10.2018
Сообщений: 2,517
02.08.2020, 16:51 2

Не по теме:

Очередная тема без конкретного примера?


Цитата Сообщение от titan4ik Посмотреть сообщение
для сортировки массива этих объектов
Цитата Сообщение от titan4ik Посмотреть сообщение
но сообщаю - эти объекты с рекурсией
Причем тут сортировка и рекурсия? Сравнение 2-ух объектов происходит по какому то конкретному значению / полю / свойству.
Цитата Сообщение от titan4ik Посмотреть сообщение
IComparable
Ну реализуйте метод CompareTo, проблема в чем?
Цитата Сообщение от titan4ik Посмотреть сообщение
IComparer
Ну реализуйте метод Compare, проблема в чем?
Цитата Сообщение от titan4ik Посмотреть сообщение
А может и ещё что-то есть
Есть базовый метод, производный от object называет Equals
Если еще перегруженный оператор == и ему подобные
Цитата Сообщение от titan4ik Посмотреть сообщение
Какой из них использовать?
Любой
Цитата Сообщение от titan4ik Посмотреть сообщение
но захотелось сделать правильно
Нет такого понятия, есть факты
0
802 / 352 / 29
Регистрация: 08.01.2017
Сообщений: 2,387
02.08.2020, 17:24  [ТС] 3
Цитата Сообщение от Enifan Посмотреть сообщение
Очередная тема без конкретного примера?
ОК, давайте рассмотрим такой пример.
Допустим, что речь о сортировке массива объектов вот такого класса:
Кликните здесь для просмотра всего текста
C#
1
2
3
4
5
6
class Matryoshka
    {        
        public string Name { get; set; }
        public double [] Params { get; set; }
        public Matryoshka[] Mats { get; set; }
    }

P.S. Порядок элементов в массиве Mats каждого объекта не важен с точки зрения сравнения. Эти массивы не упорядоченные. Важен только набор элементов.

Добавлено через 4 минуты
Цитата Сообщение от Enifan Посмотреть сообщение
Ну реализуйте метод CompareTo, проблема в чем?
Цитата Сообщение от Enifan Посмотреть сообщение
Ну реализуйте метод Compare, проблема в чем?
Раз есть два интерфейса и соответственно два метода, то вероятно, они отличаются чем-то. По каким критериям выбирать что использовать?
А других аналогичных интерфейсов нет? Может выбор ещё шире?

Добавлено через 10 минут
Пардон, я понял увидел в чем формальная разница этих двух интерфейсов.
0
756 / 453 / 235
Регистрация: 26.11.2015
Сообщений: 1,454
Записей в блоге: 2
02.08.2020, 18:19 4
IComparable - это вы учите объект сравнивать самого себя с другим объектом этого класса. Этот метод будет использоваться, если при сортировке вы не укажете явно компаратор. Соответственно IComparer - обычно реализуют у отдельного класса (компаратора), экземпляр которого передается в методы сортировки
1
802 / 352 / 29
Регистрация: 08.01.2017
Сообщений: 2,387
02.08.2020, 20:24  [ТС] 5
И всё-таки не понимаю по документации что и как. Ну их к чёрту. Сделаю без интерфейсов свои собственные методы.
0
756 / 453 / 235
Регистрация: 26.11.2015
Сообщений: 1,454
Записей в блоге: 2
02.08.2020, 20:47 6
Лучший ответ Сообщение было отмечено titan4ik как решение

Решение

Вот простенький пример.
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
    class Person : IComparable<Person>
    {
        public int Age { get; set; }
        public string Name { get; set; }
 
        public Person(int age, string name)
        {
            Age = age;
            Name = name;
        }
 
        public int CompareTo(Person other)
        {
            return Age.CompareTo(other.Age);
        }
 
        public override string ToString()
        {
            return Name;
        }
    }
 
    class NameComparer : IComparer<Person>
    {
        public int Compare(Person x, Person y)
        {
            return x.Name.CompareTo(y.Name);
        }
    }
 
    class Program
    {
        static void Main(string[] args)
        {
            var Persons = new List<Person>() { new Person(2, "B"), new Person(1, "C"), new Person(3, "A") };
            Persons.Sort();
            foreach (var item in Persons)
                Console.WriteLine(item);
 
            Console.WriteLine();
 
            Persons.Sort(new NameComparer());
            foreach (var item in Persons)
                Console.WriteLine(item);
 
        }
    }
1
802 / 352 / 29
Регистрация: 08.01.2017
Сообщений: 2,387
02.08.2020, 23:07  [ТС] 7
Спасибо, Toros1992, кое о чем стал хоть догадываться.
P.S. Жаль, что документацию пишут нечеловеческим языком (точнее - её пишут для тех, кто и так всё знает уже, многое остается между строк).

Добавлено через 1 час 19 минут
подброшу ещё одну старую ссылку до кучи ("замутим для ясности"):
https://habr.com/ru/post/137680/
0
943 / 717 / 342
Регистрация: 30.10.2017
Сообщений: 2,088
02.08.2020, 23:11 8
Цитата Сообщение от titan4ik Посмотреть сообщение
Жаль, что документацию пишут нечеловеческим языком
Книги можно почитать. Например, у Троелсена основные интерфейсы достаточно подробно разжеваны и с примерами.
1
802 / 352 / 29
Регистрация: 08.01.2017
Сообщений: 2,387
03.08.2020, 00:32  [ТС] 9
Цикл статей о сравнении объектов
Ссылка на первую статью
https://habr.com/ru/post/314328/

Добавлено через 47 минут
Почитал первые две статьи этого цикла... ёшкин кот...
Интересно, в с++ такая же лабуда или там всё немного корректнее и однозначнее?)

Добавлено через 30 минут
Цитата Сообщение от QuakerRUS Посмотреть сообщение
у Троелсена основные интерфейсы достаточно подробно разжеваны и с примерами.
QuakerRUS, спасибо. Мне понравилось. Надо бы потом полностью его прочитать - понравился подход к изложению материала. Сразу видно, что в голове у автора порядок (и реально глубоко просекает тему). Вроде и переводчик не налажал.
0
802 / 352 / 29
Регистрация: 08.01.2017
Сообщений: 2,387
04.08.2020, 16:47  [ТС] 10
Спасибо всем, вроде некое понимание куда двигаться появилось.
Однако, в документации пишут, что РЕКОМЕНДУЕТСЯ:
"Рекомендуется наследовать от класса Comparer<T>, а не реализовывать интерфейс IComparer<T>, так как класс Comparer<T> предоставляет явную реализацию интерфейса IComparer.Compare метода и свойство Default, которое получает компаратор по умолчанию для объекта."
При этом, в Троелсене пример на основе использования наследования от интерфейса.
Посмотрел код Comparer<T> - мне, мягко говоря, не всё там понятно. Опасаюсь чуток непонятного.
Куда понятнее код интерфейса IComparer<T>!
Какие существенные минусы использования интерфейса IComparer<T>, а не абстрактного класса Comparer<T>?
P.S. Я код исключительно для себя пишу.
0
943 / 717 / 342
Регистрация: 30.10.2017
Сообщений: 2,088
04.08.2020, 17:51 11
titan4ik, не вижу тут сложностей переделать пример Троелсена для наследования от Comparer<T>. Visual Studio половину работы за вас сделает, а именно реализует дефолтный метод.

C#
1
2
3
4
5
6
7
class PetNameComparer : Comparer<Car>
{
    public override int Compare(Car x, Car y)
    {
        throw new NotImplementedException();
    }
}
Осталось только кусок кода из примера подставить в этот метод.

C#
1
2
3
4
5
6
7
8
9
10
class PetNameComparer : Comparer<Car>
{
    public override int Compare(Car x, Car y)
    {
        if (x != null && y != null)
            return String.Compare(x.PetName, y.PetName);
        else
            throw new ArgumentException("Parameter is not a Car!");
    }
}
1
802 / 352 / 29
Регистрация: 08.01.2017
Сообщений: 2,387
04.08.2020, 18:07  [ТС] 12
Цитата Сообщение от QuakerRUS Посмотреть сообщение
Осталось только кусок кода из примера подставить в этот метод.
Только код из примера для необобщенного Compare не вяжется с обобщенным.
C#
1
2
3
4
if (x != null && y != null)
            return String.Compare(x.PetName, y.PetName);
        else
            throw new ArgumentException("Parameter is not a Car!");
Для вашего варианта с обобщенным Compare<T>, если даже один из параметров null, это не значит, что "Parameter is not a Car!"
Но это не меняет суть ответа на вопрос. То есть, вы тоже за Compare<T>
0
943 / 717 / 342
Регистрация: 30.10.2017
Сообщений: 2,088
04.08.2020, 18:12 13
Цитата Сообщение от titan4ik Посмотреть сообщение
Только код из примера для необобщенного Compare не вяжется с обобщенным.
А при чем тут необобщенный Compare? Вы сами процитировали:

Цитата Сообщение от titan4ik Посмотреть сообщение
Рекомендуется наследовать от класса Comparer<T>
Цитата Сообщение от titan4ik Посмотреть сообщение
Для вашего варианта с обобщенным Compare?
Не понял, что вы хотите сказать. В данном случае <Car> и есть обобщение.

Цитата Сообщение от titan4ik Посмотреть сообщение
если даже один из параметров null, это не значит, что "Parameter is not a Car!"
Я просто скопипастил кусок отсюда, лишнее можно удалить:

C#
1
2
3
4
5
6
7
8
9
10
11
12
class PetNameComparer : IComparer
{
    int IComparer.Compare(object o1, object o2)
    {
        Car t1 = o1 as Car;
        Car t2 = o2 as Car;
        if (t1 != null && t2 != null)
            return String.Compare(t1.PetName, t2.PetName);
        else
            throw new ArgumentException("Parameter is not a Car!");
    }
}
0
802 / 352 / 29
Регистрация: 08.01.2017
Сообщений: 2,387
04.08.2020, 18:19  [ТС] 14
В случае использования обобщенного Comparer<T>, наверное достаточно такого кода:
C#
1
2
3
4
5
6
7
class PetNameComparer : Comparer<Car>
{
    public override int Compare(Car x, Car y)
    {       
            return String.Compare(x.PetName, y.PetName);       
    }
}
0
943 / 717 / 342
Регистрация: 30.10.2017
Сообщений: 2,088
04.08.2020, 18:19 15
Цитата Сообщение от QuakerRUS Посмотреть сообщение
Только код из примера для необобщенного Compare не вяжется с обобщенным.
Или вы про сам метод? Тогда я не пойму вашей логики. Запустите пример и посмотрите у себя, у меня все работает.
0
802 / 352 / 29
Регистрация: 08.01.2017
Сообщений: 2,387
04.08.2020, 18:25  [ТС] 16
Всё будет работать, но логика не вполне корректная.
В примере у Троелсена проверка на null проверяет результат приведения типа
А в случае исп обобщенного Comparer<Car> приведение типа не нужно вообще, значит не нужна и проверка. А если параметр имеет значение null, то это учитывается уже внутри стандартного String.Compare(x.PetName, y.PetName);
Мне так кажется.
0
943 / 717 / 342
Регистрация: 30.10.2017
Сообщений: 2,088
04.08.2020, 18:26 17
Цитата Сообщение от titan4ik Посмотреть сообщение
наверное достаточно такого кода
Можно и так, если не нужно проверку на существование объекта делать. В примере Троелсена он скорее был сделан, чтобы проверить, что передали корректный класс, так как аргументы типа object передаются, то есть метод не строго типизирован. Здесь же метод строго типизирован, риск только в том, что могут передать null, но тут, думаю, логичнее будет использовать дефолтный эксепшен.
0
802 / 352 / 29
Регистрация: 08.01.2017
Сообщений: 2,387
04.08.2020, 20:39  [ТС] 18
ок.

Добавлено через 1 час 28 минут
Цитата Сообщение от titan4ik Посмотреть сообщение
Вижу, что есть два интерфейса: IComparable и IComparer
А может и ещё что-то есть (не знаю).
Какой из них использовать?
Отвечаю на свои вопросы так, как я в итоге понял:
1. Да есть "кое-что ещё". Это абстрактный класс Comparer
2. Использовать проще обобщенные варианты интерфейса и класса
3. Вместо интерфейса IComparer лучше использовать абстрактный класс Comparer - с учетом пункта 2. - в обобщенном варианте - Comparer<T>.
4. Если использовать и IComparable<T> и Comparer<T>, то с пом IComparable<T> (применяется непосредственно к классу сравниваемого объекта) задается сравнение по умолчанию (оно будет использовать, например, если будут использоваться стандартные методы Sort() без параметров), а с пом Comparer<T> определяются специальные классы-компараторы, которые могут задавать иные способы сравнения объектов типа Т.
Об этом в документации:
Используйте класс, производный от этого класса (мой коммент - имеется ввиду класс Comparer<T>) - , чтобы предоставить пользовательскую реализацию интерфейса IComparer<T> для использования с классами коллекций, такими как SortedList<TKey,TValue> и SortedDictionary<TKey,TValue> универсальные классы.

Различие между наследованием от класса Comparer<T> и реализацией интерфейса System.IComparable выглядит следующим образом:

- Чтобы указать, как два объекта должны сравниваться по умолчанию, реализуйте интерфейс System.IComparable в своем классе. Это гарантирует, что в операциях сортировки будет использоваться указанный по умолчанию код сравнения.

- Чтобы определить компаратор для использования вместо компаратора по умолчанию, следует использовать класс, производный от класса Comparer<T>. Затем это средство сравнения можно использовать в операциях сортировки, принимающих компаратор в качестве параметра.
Добавлено через 25 минут
Осталась одна деталь,
насколько понимаю, при реализации в пользовательском классе-компараторе метода Compare (public override int Compare(T x, T y)) абстрактного класса Compare<T> можно использовать стандартные методы для стандартных типов - и Compare, и CompareTo - никакой разницы вроде нет. Правильно?

Добавлено через 17 минут
Но использовать CompareTo вроде как-то симпатичнее. В примере в док используется именно CompareTo.
0
943 / 717 / 342
Регистрация: 30.10.2017
Сообщений: 2,088
04.08.2020, 20:56 19
Цитата Сообщение от titan4ik Посмотреть сообщение
никакой разницы вроде нет. Правильно?
CompareTo вызывается через объект, в этом его плюс.
1
802 / 352 / 29
Регистрация: 08.01.2017
Сообщений: 2,387
04.08.2020, 21:09  [ТС] 20
Цитата Сообщение от QuakerRUS Посмотреть сообщение
CompareTo вызывается через объект, в этом его плюс.
Почему это плюс?

Добавлено через 8 минут
вот этот код из примера док наверное можно упростить?
Кликните здесь для просмотра всего текста
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public int CompareTo(Box other)
    {
        // Compares Height, Length, and Width.
        if (this.Height.CompareTo(other.Height) != 0)
        {
            return this.Height.CompareTo(other.Height);
        }
        else if (this.Length.CompareTo(other.Length) != 0)
        {
            return this.Length.CompareTo(other.Length);
        }
        else if (this.Width.CompareTo(other.Width) != 0)
        {
            return this.Width.CompareTo(other.Width);
        }
        else
        {
            return 0;
        }
    }

Во-первых this тут не нужны, а во-вторых "else" можно удалить:
Кликните здесь для просмотра всего текста
C#
1
2
3
4
5
6
7
8
public int CompareTo(Box other)
    {
        // Compares Height, Length, and Width.
        if (Height.CompareTo(other.Height) != 0) return Height.CompareTo(other.Height);
        if (Length.CompareTo(other.Length) != 0) return Length.CompareTo(other.Length);
        if (Width.CompareTo(other.Width) != 0) return Width.CompareTo(other.Width);       
        return 0;        
    }

Возражений нет?
0
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
04.08.2020, 21:09

Заказываю контрольные, курсовые, дипломные и любые другие студенческие работы здесь.

Дополнительный метод сравнения объектов класса
Имеется класс для которого уже реализован интерфейс Comparable и перегружен метод compareTo....

Вектор объектов пользовательского класса
Привет всем! Есть класс Automaton, я пытаюсь создать вектор Sample с объектами этого класса, а они...

Подсчет созданных объектов пользовательского класса
Создать класс SIGMOID таким образом, чтобы при уничтожении последнего объекта на экран выдавалось...

Очистка вектора объектов пользовательского класса
Здравствуйте. Есть вектор std::vector&lt;Morphology*&gt; MorphCollection который заполняется следующим...

Организация коллекции объектов пользовательского класса
Есть некий пользовательский класс Mob. И есть класс MobAssistant, существующий для управления...

Вставка и удаление объектов пользовательского класса в deque
Доброго времени суток! У меня есть контейнер хранящий объекты пользовательского класса Detail:...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2020, vBulletin Solutions, Inc.