Проблема сортировки 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

Другие вопросы по тегам