Welcome to
aleprojects.com

Ассоциативный массив. Классы TAleArray и TAleValue.

Ассоциативный массив - это структура данных, позволяющая хранить пары Ключ-Значение. Данная реализация позволяет использовать целочисленные и строковые ключи. Использование ключей других типов возможно, но необходимо расширение класса, реализующего массив. Быстрый доступ к элементам по ключам осуществляется при помощи красно-черного дерева (RB-дерево). Значениями элементов ассоциативного массива являются экземпляры класса TObject или его потомки. В том числе, значением может быть и сам класс TAleArray. Таким образом реализуются вложенные массивы.

Функциональность ассоциативного массива (добавление, удаление, сортировка и обход элементов) реализует класс TAleArray. Класс TAleValue создан для удобства хранения одиночных значений типа: Boolean, LongInt, Int64, Double, Currency, TDateTime, PWideChar. Значения массива типа TAleValue могут быть корректно сравнены между собой и отсортированы.

Скачать

Пример

var A:TAleArray;
    V:TAleValue;

begin
//создать массив
A := TAleArray.Create;

//создать первый элемент массива с ключем 'Key_0' и целочисленным значением
V := TAleValue.Create;
V.IntegerValue := 100;
A['Key_0'] := V;

//создать второй элемент массива с ключем 1 и текстовым значением
V := TAleValue.Create;
V.TextValue := AleWSNew(PWideChar(WideString('Some text')));
A.ByIntKey[1] := V;

//создать третий элемент массива с ключем 'Key_1' и текстовым значением
V := TAleValue.Create;
V.TextValue := AleWSNew(PWideChar(A['Key_0'].AsText + ' ' + A.ByIntKey[1].AsText));
A['Key_1'] := V;

//удалить второй элемент
A.ByIntKey[1] := nil;
...
A.Free;
end;

Комментарии

Доступ к элементу с текстовым ключем - A['Key_0'], а с целочисленным - A.ByIntKey[1]. Класс TAleValue содержит свойство ByTextKey. В описании класса свойство указано как default. Функция AleWSNew (соответствующий unit прилагается) - формат строк для свойства TextValue класса TAleValue должен соответствовать формату WideString. 4 байта перед указателем - длина строки, умноженная на SizeOf(WideChar) = 2 и завершающий #0.

Использование

Для использования ассоциативного массива необходимо определить переменную типа TAleArray .

var A, A1: TAleArray;
    N: LongInt;
...
A := TAleArray.Create;
A1 := TAleArray.Create;
A['Item_0'] := A1;
N := A.Count;
...

Добавление и доступ к элементам массива

Доступ к элементам ассоциативного массива осуществляется с помощью свойств ByTextKey[const Key:WideString]:TObject;default; и ByIntKey[Key:LongInt]:TObject. Если элемент с заданным ключем не существует, свойства возвращают nil. При присвоении значения свойствам происходит следующее: если элемента с указанным ключем нет, он создается; если элемент есть, устанавливается новое значение элемента; если свойству присваивается значение nil, то элемент с указанным ключем удаляется из массива. Текстовые ключи регистронезависимы.

Метод Add добавляет в массив новый элемент и устанавливает ему целочисленный ключ со значением на 1 большим максимального из имеющихся в массиве целочисленных ключей.

procedure TAleArray.Add(NewValue:TAleValue);

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

var A,V: TAleValue;
    i: LongInt;
...
A := TAleValue.CreateArray;
V := TAleValue.Create;
V.IntegerValue := 525;

A['Level0;Level1;Level2'] := V;
...
i := A['Level0;Level1;Level2'].IntegerValue;
// или так
i := TAleValue(TAleArray(TAleArray(A['Level0'])['Level1'])['Level2']).IntegerValue;

В массиве A будет создан элемент с ключем 'Level0', являющийся массивом, в котором, в свою очередь будет создан элемент-массив с ключем 'Level1', и в нем будет создан элемент с ключем 'Level2', содержащий значение 525. Разделитель ключей (';') задается свойством IndexSeparator:WideChar. Данный способ работает только для текстовых ключей.

Количество элементов массива можно узнать из свойства Count класса TAleAssociativeArray.

Обход элементов

Обход элементов ассоциативного массива осуществляется методом GetNext класса TAleArray. Элементы располагаются в том порядке, в котором они были добавлены в массив. Метод GetNext определен как

function TAleArray.GetNext(var O:TObject; var lpKey:Pointer; var KeyType:Longint):Boolean;

в параметре O возвращается значение следующего элемента,
в параметре lpKey возвращается указатель на значение ключа (указатель может быть как на строку PWideChar, так и на число LongInt),
в параметре KeyType возвращается тип ключа (0 - целочисленный ключ (константа aa_intkey), 1 - текстовый (константа aa_textkey) для правильной интерпретации указателя lpKey.

Метод возвращает false, если элементов больше нет. Для обхода массива с начала необходимо при первом вызове GetNext установить параметр O равным nil.

var V: TObject;
    A: TAleArray;
    wS: WideString;
    lpKey: Pointer;
    i:LongInt;
...	

//вывести содержимое массива в Memo1
V := nil;
While A.GetNext(V, lpKey, i) do
 begin
   if i = aa_intkey then wS := IntToStr(Integer(lpKey^)) else wS := WideString(PWideChar(lpKey));
   wS := '[' + wS + '] => ';
   if V is TAleValue then wS := wS + V.AsText else wS := wS + 'Some object';
   Memo1.Lines.Append(wS);
 end;

Сортировка массива

Сортировка осуществляется методом Sort класса TAleArray.

procedure TAleArray.Sort(dwParam:Longint=0);

В параметре dwParam старший бит зарезервирован и определяет порядок сортировки (0 - по возрастанию, 1 - по убыванию). Значение dwParam передается в виртуальный метод ArrayCompareElements, осуществляющий сравнение элементов массива между собой. Метод может быть переопределен в классе-наследнике TAleArray.

Сортировка нарушает порядок следования элементов массива. До сортировки элементы располагаются в порядке добавления. Добавление элементов или установка их новых значений после сортировки в общем случае нарушает порядок сортировки.

После сортировки элементы массива будут располагаться в следующей последовательности типов: сначала идут значения массива типа TAleValue, которые в свою очередь упорядочены в последовательности Boolean, [Числовые типы], ДатаВремя, Текст, затем остальные значения в случайном порядке. И наоборот, если сортировка по убыванию. Чтобы изменить последовательность типов или сравнивать между собой значения с типами, отличными от TAleValue, следует переопределить метод ArrayCompareElements.

массив упорядоченный по возрастанию

[false, false, true, 0, 0.1, 2, 10, 1.344E+23, 03-mar-1999, 09-aug-2010, 'AAA', 'aaa', 'dd', 'zz', TObject2, TObject1]

Метод Sort основан на алгоритме QuickSort. Для сортировки требуется дополнительная память. Если ассоциативный массив содержит N элементов, то будет выделена память объемом N*SizeOf(Pointer) байт. Это связано с тем, что порядок следования элементов массива задается двунаправленным списком, а не индексным массивом.

var A: TAleArray;
...
//по возрастанию
A.Sort; 
//по убыванию
A.Sort($80000000); 
...

Работа с ключами массива

Метод Keys возвращает все ключи в виде массива.

function TAleArray.Keys(bOrdered:Boolean=true):TAleArray;

Элементы возвращаемого массива имеют только целочисленные ключи 0..N-1. Где N количество элементов исходного массива. Если параметр bOrdered равен false, то элементы в возвращаемом массиве расположены в том же порядке, что и элементы исходного массива. Иначе они упорядочены по возрастанию значения ключа.

Очистка, уничтожение массива и ссылки

Для удаления всех элементов массива предназначен метод Clear. При удалении элементов массива для каждого элемента вызывается метод Free. После очистки или уничтожения массива все ссылки на элементы массива, полученные ранее, станут недействительными.