Окно списка по убыванию Элементы Delphi XE8

Я просматривал некоторые вопросы о том, как сортировать элементы списка в нисходящей последовательности. Кажется, что по умолчанию и единственная последовательность является возрастающей. У нас есть набор строк (TStringList).

Мне кажется, что если мы вставим цель сортировки в список коллекции, выполним сортировку (в порядке возрастания), но получим доступ к отсортированным элементам в порядке убывания и добавим их в элемент несортированного списка после удаления ключа, что мы получить желаемый нисходящий эффект.

procedure TBCSLBDemoC.DescendLZB(var lb: TListBox);
var
  sc: TStringList;
  i: Integer;
  rdt: TDateTime;
  buf : string;
begin
  sc := TStringList.Create;
  i := 0;
  repeat
    rdt := TFile.GetLastAccessTime(lb.Items[i]);
    sc.Add(FormatDateTime('YYYYMMDDHHMMSS', rdt) + ' ' + lb.Items[i]);
    Inc(i);
  until (i > (lb.Count - 1));
  sc.Sort;
  lb.Sorted := false;
  lb.Items.Clear;
  i := sc.Count - 1;
  repeat
    buf := sc[i];
    Delete(buf, 1, 15);
    lb.Items.Add(buf);
    dec(i);
  until (i < 0);
  sc.Free;
end;

Эти результаты, казалось, работали хорошо для меня, но мой вопрос в том, как я мог бы улучшить эту технику? Я считаю, что я что-то упустил.,


person Arch Brooks    schedule 30.09.2015    source источник


Ответы (1)


Есть много разных способов решить эту проблему. Вы показали один метод. Вы можете переключиться на виртуальный список и сохранить данные в упорядоченной структуре данных. Вы можете отсортировать список на месте.

Лично меня немного тошнит от вашего кода, который создает новый список для выполнения сортировки. И еще более тошнотворным из-за того, что вы используете текстовые представления метки времени. Если у вас большое количество элементов в списке, то виртуальный режим более эффективен.

Однако я покажу очень гибкий способ сортировки списка на месте. Начнем с кода из моего ответа здесь: https://stackoverflow.com/a/21702570/505088. Для большей самодостаточности воспроизведем приведенный здесь код, немного изменив его для использования эталонных процедур:

type
  TCompareIndicesFunction = reference to function(Index1, Index2: Integer): Integer;
  TExchangeIndicesProcedure = reference to procedure(Index1, Index2: Integer);

procedure QuickSort(Count: Integer; Compare: TCompareIndicesFunction; 
  Exchange: TExchangeIndicesProcedure);

  procedure Sort(L, R: Integer);
  var
    I, J, P: Integer;
  begin
    repeat
      I := L;
      J := R;
      P := (L+R) div 2;
      repeat
        while Compare(I, P)<0 do inc(I); 
        while Compare(J, P)>0 do dec(J); 
        if I<=J then 
        begin
          if I<>J then 
          begin
            Exchange(I, J);
            //may have moved the pivot so we must remember which element it is
            if P=I then
              P := J
            else if P=J then
              P := I;
          end;
          inc(I);
          dec(J);
        end;
      until I>J;
      if L<J then 
        Sort(L, J); 
      L := I;
    until I>=R;
  end;

begin
  if Count>0 then
    Sort(0, Count-1);
end;

Ключевая идея здесь в том, что алгоритм сортировки отделен от хранилища данных. Именно это дает нам гибкость.

Далее нам нужно реализовать функции сравнения и обмена. Как это:

var
  Compare: TCompareIndicesFunction;
  Exchange: TExchangeIndicesProcedure;

Compare := 
  function(Index1, Index2: Integer): Integer
  var
    dt1, dt2: TDateTime;
  begin
    dt1 := TFile.GetLastAccessTime(lb.Items[Index1]);
    dt2 := TFile.GetLastAccessTime(lb.Items[Index2]);
    if dt1=dt2 then begin
      Result := 0;
    end else if dt2<dt1 then begin
      Result := -1
    end else begin
      Result := 1;
    end;
  end;

Exchange := 
  procedure(Index1, Index2: Integer)
  begin
    lb.Items.Exchange(Index1, Index2);
  end;

Обратите внимание, что я сравниваю числовое значение метки времени, что кажется гораздо более приятным. Если у меня есть порядок в обратном порядке (я всегда борюсь с функциями сравнения сортировки), тогда должно быть очевидно, как его изменить.

И, наконец, мы можем отсортировать так:

QuickSort(lb.Count, Compare, Exchange);

Этот код следует поместить внутрь вашего DescendLZB, чтобы он мог захватывать список. Кроме того, параметр lb не должен быть параметром var, поскольку вы не хотите изменять его значение.

Все вместе тогда это будет выглядеть так:

procedure TBCSLBDemoC.DescendLZB(lb: TListBox);
var
  Compare: TCompareIndicesFunction;
  Exchange: TExchangeIndicesProcedure;
begin
  Compare := 
    function(Index1, Index2: Integer): Integer
    var
      dt1, dt2: TDateTime;
    begin
      dt1 := TFile.GetLastAccessTime(lb.Items[Index1]);
      dt2 := TFile.GetLastAccessTime(lb.Items[Index2]);
      if dt1=dt2 then begin
        Result := 0;
      end else if dt2<dt1 then begin
        Result := -1
      end else begin
        Result := 1;
      end;
    end;

  Exchange := 
    procedure(Index1, Index2: Integer)
    begin
      lb.Items.Exchange(Index1, Index2);
    end;
  end;

  QuickSort(lb.Count, Compare, Exchange);
end;
person David Heffernan    schedule 30.09.2015