Отсортированные наборы
-----------------------------------------------------------------
Иногда вам бывает нужно, чтобы ваши данные были определенным образом отсортированы. ObjectWindows имеет специальный тип набо- ра, который позволяет вам упорядочить ваши данные произвольным образом. Это тип TSortedCollection.
TSortedCollection является производным от TCollection и ав- томатически сортирует задаваемые ему объекты. При добавлении но- вого элемента он автоматически проверяет набор на дублирование ключей. Булевское поле Duplicates контролирует разрешение дубли- рования ключей. Если для поля Duplicates установлено значение False (по умолчанию), то новый элемент добавляется к набору, за- меняя существующий член с тем же самым ключом. Если Duplicates имеет значение True, то новый член просто вставляется в набор.
TSortedCollection - это набор абстрактного типа. Для его ис- пользования вы должны сначала решить, какой тип данных вы собира- етесь собирать и определить два метода, отвечающих вашим конкрет- ным требованиям сортировки. Для этого вам нужно создать новый тип, производный от TSortedCollection. В данном случае назовем его TClientCollection. Ваш TClientCollection уже знает, как де- лать всю реальную работу с набором. Он может вставить (Insert) запись о новом клиенте и удалять (Delete) существующие записи - он унаследовал эти основные черты поведения от TCollection. Все что нужно сделать - это научить TClientCollection, какое поле ис- пользовать в качестве ключа сортировки и как сравнивать двух кли- ентов при решении вопроса о том, какой из них должен стоять в на- боре выше другого. Это делается переписыванием методов KeyOf и Compare и реализации их следующим образом:
PClientCollection = ^TClientCollection; TClientCollection = object(TSortedCollection) function KeyOf(Item: Pointer): Pointer; virtual; function Compare(Key1, Key2: Pointer): Integer; virtual; end;
function TClientCollection.KeyOf(Item: Pointer): Pointer; begin KeyOf := PClient(Item)^.Account; end;
function TClientCollection.Compare(Key1, Key2: Pointer): Integer; begin Compare := StrIComp(PChar(Key1), PChar(Key2)); end;
Примечание: Так как ключи являются нетипизированными указателями, для них нужно выполнять приведение типа.
KeyOf определяет, какое поле или поля используются в качест- ве ключей сортировки. В данном случае это поле клиента Account. Compare воспринимает два ключа сортировки и определяет, какой из них должен идти первым в соответствии с правилами сортировки. Compare возвращает -1, 0 или 1 в зависимости от того, Key1 мень- ше, равен или больше Key2, соответственно. В данном примере ис- пользуется сортировка по алфавиту (для букв верхнего и нижнего регистра) ключевой строки (Account) путем вызова модуля Strings функции StrIComp. Вы можете легко сортировать набор по именам, вместо номера счета, если замените возвращаемое KeyOf поле на Name.
Обратите внимание на то, что ключи, возвращаемые KeyOf и пе- редаваемые в Compare являются нетипизированными указателями, поэ- тому до их разыменования и передачи в StrIComp в данном примере вы должны привести их тип к PChar.
Это практически все, что вам нужно определить! Теперь, если вы переопределите ClientList как PClientCollection вместо PCollection (сменив объявление var и вызов New), то легко сможете распечатать ваших клиентов в алфавитном порядке (COLLECT2.PAS):
var ClientList: PClientCollection; . . begin ClientList:=New(PClientCollection, Init(10,5)); . . end.
Обратите внимание и на то, как легко будет сменить сортиров- ку списка клиентов по номеру счета на сортировку по имени. Все что вам нужно сделать, это сменить метод KeyOf на возврат поля Account на поле Name.