Есть ли у Delphi 5 отсортированный словарный контейнер? - PullRequest
3 голосов
/ 12 августа 2011

Я новичок в Delphi 5 и ищу контейнер (в идеале встроенный), который будет выполнять ту же работу, что и map в C ++ (т.е. отсортированный словарь).Я сделал предварительный поиск в Google, но ничего очевидного, похоже, не предлагает.Пожалуйста, кто-нибудь может указать мне правильное направление?

Ответы [ 4 ]

3 голосов
/ 12 августа 2011

Взгляните на нашу TDynArray оболочку.

Это оболочка вокруг любого существующего динамического массива (включая динамический массив записей), который добавит TList -подобные методы к динамическому массиву.С еще большим количеством функций, таких как поиск, сортировка, хеширование и двоичная сериализация.Вы можете установить емкость массива с помощью внешней переменной Count, чтобы вставка была намного быстрее.

type
   TGroup: array of integer;
var
   Group: TGroup;
   GroupA: TDynArray;
   i, v: integer;
   Test: RawByteString;
begin
  GroupA.Init(TypeInfo(TGroup),Group); // associate GroupA with Group
  for i := 0 to 1000 do begin
    v := i+1000; // need argument passed as a const variable
    GroupA.Add(v);
  end;
  v := 1500;
  if GroupA.IndexOf(v)<0 then // search by content
    ShowMessage('Error: 1500 not found!');
  for i := GroupA.Count-1 downto 0 do
    if i and 3=0 then
      GroupA.Delete(i); // delete integer at index i
  Test := GroupA.SaveTo; // serialization into Test
  GroupA.Clear;
  GroupA.LoadFrom(Test);
  GroupA.Compare := SortDynArrayInteger;
  GroupA.Sort; // will sort the dynamic array according to the Compare function
  for i := 1 to GroupA.Count-1 do
    if Group[i]<Group[i-1] then
      ShowMessage('Error: unsorted!');
  v := 1500;
  if GroupA.Find(v)<0 then // fast binary search
    ShowMessage('Error: 1500 not found!');

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

Работает с Delphi 5 до XE.

Я считаю, что это даже проще в использовании, чем универсальные (например, для функции автосериализации),;)

См. http://blog.synopse.info/post/2011/03/12/TDynArray-and-Record-compare/load/save-using-fast-RTTI

1 голос
/ 14 августа 2011

Это может быть выполнено «из коробки» в D5 с использованием TList.Sort или TObjectList.Sort - в вашем случае вы, вероятно, захотите реализовать класс в соответствии с:

  TMyClass
   public  
      Index:integer;
      Value:TWhatever;
      ...
   end;

Чтобы сохранить в своем списке, затем реализуйте TList.Sort или TObjectList.Sort, используя значение индекса для сортировки.Это займет немного работы, но не ужасно.Подробную информацию о реализации смотрите в справке D5 по этим классам.

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

1 голос
/ 12 августа 2011

Хорошо, если D5 не содержит THashedStringList, тогда, возможно, этот (из OmniThreadLibrary) сделает работу:

https://github.com/gabr42/OmniThreadLibrary/blob/master/src/GpStringHash.pas

Я цитирую:

Протестировано с Delphi 2007. Должно работать и со старыми версиями.

Ну, ваша версия определенно старше:)

0 голосов
/ 15 августа 2011

Это возвращает воспоминания. Есть еще одна интересная техника, которая подходит для таких древних версий Delphi, как ваша. Читайте дальше!

Из вашего описания вы говорите, что хотите довольно общий контейнер, т. Е. Тот, который вы можете использовать с различными типами. Это требует использования дженериков (да, используйте новый Delphi!) Но в прежние времена был немного хакерский способ реализовать шаблоны / дженерики с Delphi до 2009 года , используя серию define с и include с. Потребовалось немного погуглить, но вот статья об этих «дженериках» очень похожа на то, что я помню. Это с 2001 года; в те дни Delphi 5 была еще недавно.

Грубая идея такова: напишите класс, который будет делать то, что вы хотите (здесь, карта от ключа к значению) для типа, и заставьте его работать. Затем измените этот файл, чтобы использовать определенное имя для типа (TMyType, что угодно), и удалите файл, чтобы он больше не был действительной единицей, а содержал только код. (Я думаю, что на самом деле два частичных файла: один для раздела interface, другой для implementation.) Включите содержимое файла, используя {$include ...}, чтобы весь ваш файл Pascal компилировался с использованием ваших определений, а затем содержимого другие частично включенные файлы, которые используют эти определения. Аккуратный, хакерский, некрасивый? Я не знаю, но это работает:)

В примере статьи создается список типизированных объектов (т. Е. Список не TObject, а TMemo, TButton и т. Д.). В результате получается файл, который выглядит следующим образом (скопировано из связанной статьи) :

unit u_MemoList;

interface

uses
  Sysutils,
  Classes,
  Contnrs,
  StdCtrls;

{$define TYPED_OBJECT_LIST_TEMPLATE}
type
  _TYPED_OBJECT_LIST_ITEM_ = TMemo;
{$INCLUDE 't_TypedObjectList.tpl'}

type
  TMemoList = class(_TYPED_OBJECT_LIST_)
  end;

implementation

{$INCLUDE 't_TypedObjectList.tpl'}

end.

Вам нужно будет написать свой собственный класс, похожий на карту, хотя вы должны иметь возможность основывать его на этом классе. Я помню, что раньше в сети был набор «универсальных» контейнеров, которые могут использовали эту технику, и я бы предположил, что среди них есть map. Боюсь, я не знаю, где он и кем он был, и поиск в Google для такого рода вещей показывает много результатов для современных версий Delphi. Лучше всего писать свои собственные.

Редактировать: Я нашел ту же статью (тот же текст и контент), но лучше отформатирован на сайте Embarcadero Developer Network .

Удачи!

...