Проблема сортировки TObjectList<T> в кластерах с одинаковым значением компаратора
Я хочу отсортировать TObjectList, используя мою собственную функцию сравнения, код функции сравнения, показанный ниже, я хочу, чтобы из моего ObjectList была возможность сортировки в двух направлениях, восходящих и нисходящих, для этого я использую SysUtil.CompareText, который имеет два параметра S1 и S2 и сортировать по убыванию, я просто опускаю знак результата CompareText, я не знаю, существует ли другое решение, все нормально, если s1 больше S2 или наоборот, однако, если s1 = s2 в обычном случае, в списке нет реиндекса потому что все элементы в столбце идентичны, но произошло противоположное, TObjectList отсортировал список, как если бы s1 > s2 или s1 Мой вопрос заключается в том, как реализовать равенство и уважение поддержки сравнения... СпасибоTPerson = class
private
FName: string;
FId: string;
public
property Name: string read FName write FName;
property ID: string read FID write FID;
end;
TPersons = class(TObjectList<TPerson>)
public
constructor Create();
procedure Sort(Direction: string); reintroduce;
end;
procedure TForm4.Button1Click(Sender: TObject);
var
PersonsList: TPersons;
I: Integer;
begin
PersonsList := TPersons.Create;
PersonsList.Sort('Ascending');
for I := 0 to PersonsList.Count - 1 do
ShowMessage(PersonsList[i].Name);
end;
{ TPersons }
constructor TPersons.Create;
var
Person: TPerson;
begin
Person := TPerson.Create;
Person.Name := 'fateh';
Person.ID := '1';
Self.Add(Person);
Person := TPerson.Create;
Person.Name := 'mohamed';
Person.ID := '1';
Self.Add(Person);
Person := TPerson.Create;
Person.Name := 'oussama';
Person.ID := '1';
Self.Add(Person);
// all ids are identical
end;
procedure TPersons.Sort(Direction: string);
var
Comparer : IComparer<TPerson>;
Comparison : TComparison<TPerson>;
begin
if Direction = 'Ascending' then
Comparison := function(const Person1, Person2 : TPerson): Integer
begin
result := CompareText(Person1.ID, Person2.ID);
end;
if Direction = 'Descending' then
Comparison := function(const Person1, Person2 : TPerson): Integer
begin
result := - CompareText(Person1.ID, Person2.ID);
end;
Comparer := TComparer<TPerson>.Construct(Comparison);
inherited Sort(Comparer);
end;
1 ответ
если s1 = s2 в обычном случае, в списке нет переиндексации, потому что все элементы в столбце идентичны
Это неправильная идея. Компьютер должен делать то, что вы сказали, но не более того. Если вы сказали компьютеру, что эти объекты равны (другими словами, функция компаратора вернула ноль), то компьютер имеет право поместить их в ЛЮБОЙ ЗАКАЗ, который соответствует его внутренней реализации сортировки.
Если вам нужен какой-то КОНКРЕТНЫЙ порядок среди кластеров объектов с одинаковым идентификатором - это просто означает, что объекты с одинаковым идентификатором НЕ ДЕЙСТВИТЕЛЬНО РАВНЫ, по крайней мере, не все из них.
Конечно, если идентификаторы отличаются - то и объекты тоже. Но даже если эти идентификаторы одинаковы - до тех пор, пока вы заботитесь об упорядочении, это просто доказывает, что эти объекты по-прежнему ОТЛИЧАЮТСЯ от вас, а равенство идентификаторов просто НЕ ДОЛЖНО указывать объекты полностью равными. А это значит, что вы должны использовать вложенный каскадный компаратор, используя все больше и больше мелкозернистых тестов, пока не обнаружите разницу.
Comparison := function(const Person1, Person2 : TPerson): Integer
begin
Result := CompareText(Person1.ID, Person2.ID);
if Result <> 0 then exit;
Result := CompareText(Person1.Name, Person2.Name);
if Result <> 0 then exit;
Result := Person1.Age - Person2.Age;
if Result <> 0 then exit;
Result := GenderCompare(Person1.Sex, Person2.Sex);
if Result <> 0 then exit;
Result := Person1.Salary - Person2.Salary;
if Result <> 0 then exit;
...et cetera
end;
Сравнение - это разновидность математики, разновидность алгебры. Вы доказываете некоторые аксиомы, а затем некоторые теории начинают работать. Но только после доказательства аксиом и не более чем теоремы.
Сам факт того, что вы заботитесь о порядке объектов с одинаковым идентификатором, показывает, что аксиома неверна. Сравнение является более сложным процессом, чем один только ID. Вы должны создать компаратор, который будет возвращать ноль только на действительно равных объектах, другими словами, на объектах, для которых соответствующий порядок вас абсолютно не интересует.
Попробуйте прочитать http://www.howzatt.demon.co.uk/articles/2011-05-equality.html