EPCL.exList - Подробнейший туториал по шаблонным спискам


Шаблонные списки в EPCL: exList


Введение

В данном документе я постараюсь подробно и понятно описать, как пользоваться компонентом TGenericList, являющимся частью EPCL и соспредоточенном в ней в исходном файле exList.pas

Подключение

Для того, чтобы использовать шаблонный список, необходимо добавить в uses ExList
uses exList

Специализация

Так как TGenericList является шаблоном, перед использованием необходимо специализировать его так:
type TMyList = specialize TGenericList<TMyType>;

ещё примеры:

type
  TMyIntegers = specialize TGenericList<integer>; //это специализирует шаблонный 
    //список на целых числах
  TMyReals = specialize TGenericList<real>; //на реальных числах
  TMyMultiIntegers = specialze TGenericList<TMyIntegers>; // на списках целых чисел,
    //а почему бы и нет?

Создание

Итак, мы объявили список. Перед использованием его надо создать одним из этих способов:

//пример для списка чисел. Для других - аналогично
var
  ints: TMyIntegers;
 
begin
  ints:=TMyIntegers.Create; //Способ #1
 
  ints:=TMyIntegers.Create(owner); //тут указываем собственника: TComponent
 
  ints:=TMyIntegers.Create([1, 2, 3, 66, 13, x, -1, -100500, a + b + 1]); 
    //очень полезный способ, который позволяет создать 
    //список и сразу запихнуть в него элементы
 
  ints:=TMyIntegers.Create(owner, [1, 2, 3, 6]); //то же, но с собственником
 
  ints:=TMyIntegers.Create(owner, @NewIntFunction, @CompareIntsFunction, @DestroyIntFunction);
    //позволяет создать список и присвоить ему функции для создания нового элемента, 
    //сравнения элементов и удаления элементов. Опционально

Добавка элементов

Итак, мы создали список. Теперь, возможно, потребуется добавить в него элементы:

  (* Способ #1 *)
ints.Add(15); //добавит элемент 15. Возвращает номер нового элемента
ints.Add(x); //Добавит элемент x Возвращает номер нового элемента
 
  (* Способ #2 *)
ints.Add([15, x, x+15, 6, 7, 8]); //Добавить несколько элементов сразу.
  //Возвращает номер последнего добавленного элемента
 
  (* Способ #3 *)
ints.NewFunction:=@CreateNewInt;
ints.AddNew(100); //добавляет  100 новых 

При этом CreateNewInt - функция вида
function CreateNewInt: integer;
begin result:=random(100); end;  
 
(* Общий вид: *) function CreateNewItem: TItem;


  (* Способ #4 - важный*)
ints.Capacity:=100;
for i:=1 to 100 do ints.add(random(100));

Если в данном примере опустить строку Capacity, то память выделится
(100 / ints._DefaultCapacityReserve) раз, где _DefaultCapacityReserve = 3 по умолчанию. То есть, около 30 раз. Что негативно отразится на скорости работы.


Обращение к элементам


ints[i]:=1;
x:=ints[6];
 
  // Примочки для первого и последнего элементов
ints.First:=0;
ints.Last:=999;
 
  //Шестой элемент с конца
ints[ints.Count - 6]:=a + b;
 
  //Проверить, существует ли элемент с номером n
var
  x: boolean;
begin
  x:=ints.ItemExists[n];
end;
 

Удаление элементов


  (* Способ #1 *)
ints.Delete(10); //удалит десятый элемент и сдвинет
  // все последующие элементы влево. Возвращает false, если десятого
  // элемента в массиве нет
 
  (* Способ #2 *)
ints.Delete([1, 3, 2]); 
  // Удалит первый, третий и второй элементы в массиве. При этом
  // не важно, что после удаления первого элемента третий станет вторым.
  // Будут удалены элементы с теми номерами, какие они имели до удаления 
  // первого элемента из группы.
 
  // Если хотябы один номер повторится два раза или хотябы одного из 
  // указанных элементов не существует, подет возвращено false
 
  (* Способ #3)
ints.DestroyItem(6); //Применяет удалитель к шестому элементу
  // при этом элемент остаётся, количество элементов не изменяется
  // Если удалитель не назначен, будет возвращено false, иначе будет 
  // возвращён результат работы удалителя

Применение удалителя:

ints.DestroyFunction:=@IntDestroyFunction;
ints.Delete(6);

Здесь к шестому элементу перед его удалением будет пременена функция-удалитель. При этом достаточно установить функцию один раз, после чего она будет применяться при удалении любого элемента из массива.

function IntDestroyFunc(var ax: integer): boolean;
begin ax:=0; end;  
 
  // Общий вид:
function ItemDestroyFunction(var aItem: TItem): boolean;
 
  (*
    Если функция-удалитель возвратит false для элемента (если удалялся один элемент) 
    или элементов (если они удалялись [,,,] группой, то Delete возвратит также false
  *)

Сортировка

Перед сортировкой элементов нужно указать свойство
SortingFunction либо SortingMethod

ints.SortingFunction:=IntCompareFunc;
ints.Sort;

где IntCompareFunc имеет вид:

  // Объявление
TCompareFunction = function(const ax1, ax2: TItem): integer;
TCompareMethod = function(const ax1, ax2: TItem): integer of object;
 
  // Общий вид
function ItemCompareFunc(const a, b: TItem): integer;
type TMyClass = class
  function ItemCompareMeth(const a, b: TItem): integer;
end;
 
  // Частный пример
function IntCompareFunc(const ax, ay: integer): integer;
begin result:=ax - ay; end; //Для сортировки по возрастанию из первого
  // вычитаем второе
 

Для сортировки по возрастанию надо возвращать

Если элементы равны
0
Если первый элемент больше
1
Если второй элемент больше
-1

  • Важно помнить, что для сортировки достаточно указать либо метод, либо функцию, но не обязательно всё сразу
При этом, если указаны оба свойства, то будет использоваться метод

Поменять местами элементы

ints.Exchange(10, 11); //Десятый поменять с одиннадцатым


Освобождение


ints.Free
FreeAndNil(ints);
 
  (* Либо удалить все элементы *)
ints.Clear; //Удалить все элементы
ints.DestroyItems //Применить удалитель ко всем элементам, но оставить их

При этом важно, что если указана DestroyFunction, то она будет применена ко всем элементам списка. Как в результате вызова Free, так и в результате вызова Clear. Иначе (если она не указана) они просто будут удалены. Если в списке были экземрляры классов, то будут удалены только ссылки на них, Free не будет применен автоматически, поэтому целесообразно освобождать их в DestroyFunction.

Текстование

Данную фичу обзовём "текстование", т.е. преобразование содержимого списка в текст: string

ints.TextFunction:=@IntToText; //Указываем функцию
 
ShowMessage(ints.AsText); //Преобразует массив в текст
 
ShowMessage(ints.AsText[tlNumbers, tlQuotes, tlBRs, tlHead]);
  //Собсна, не обязательно указывать все опции, можно что-то одно или несколько
 
ShowMessage(AsString( ['Массив как текст: ', ints, ' //Троллоло'] ));
  //Да, так тоже будет работать, но AsString требует модуль exStrings
 

Функция текстования должна преобразовывать один элемент в строку

  // пример
function IntAstextFunc(const ax: integer): string;
begin  result:=AsString(ax);  end; 
 
  // общий вид
function ItemAsText(const aItem: TItem): string

При вызове метода AsText можно указать формат преобразования (а можно и не указывать). Вот описание возможных элементов множества
tlNumbers
Ставить номера возле элементов
tlQuotes
Окружать элементы кавычками
tlBRs
Каждый элемент на новой строке
tlHead
Заголовок списка, включающий в себя его ClassName, Name(если имеется) и количество элементов
Home
Loading...
Home Turn Off "Getting Started"
Loading...