Класс для RSL, реализующий ассоциативные массивы с предопределёнными типами ключей и значений.

Автор:tema
Дата:11.01.2016
Просмотров:2873
Скачиваний:515
Оценка:, Оценок - 1
Скачать (zip-файл; Размер - 492629)

Обсудить в форуме

Описание

Класс для RSL, реализующий ассоциативные массивы с предопределёнными типами ключей и значений.
Класс
Тип ключа
Тип значения
TAssArraySI
String
Integer
TAssArraySS
String
String
TAssArraySD
String
Money
TAssArraySO
String
Object
TAssArrayIS
Integer
String
TAssArrayS
String

TassArrayI
Integer

TBoostBiMapSI
String
Integer
TBoostBiMapSS
String
String
Для класса TAssArraySD в большинстве случаев поддерживается автоматическая конвертация входных параметров значений в тип Money.
Класс TAssArraySO экспериментальный, может приводить к утечкам памяти и прочим подаркам.
Поскольку RSL case insensitive название DLM и объектов следует читать как T[ema]‑Assa‑R‑ray :)
Новое семейство классов TBoostBiMap это ассоциативные массивы с обратной связью, ключи в этом наборе уникальны, значения — нет. Для этих классов есть дополнительные методы с суффиксом R, реализующие поиск не по ключу, а по значению.
TAssArray ключ → значение
TBoostBiMap ключ ↔ значение
Методы и свойства
DelAll
Очищает массив. Удаляет все элементы.
Возвращаемое значение: нет
Insert(key, value)
Вставляет пару ключ-значение. Если ключ существует, то значение не заменяется.
Возвращаемое значение: нет
InsertM(key, value, key, value, key, value,..)
Вставляет пару ключ-значение. Если ключ существует, то значение не заменяется. Позволяет указать произвольное количество пар ключ-значение.
Возвращаемое значение: нет
Get(key)
Возвращаемое значение: value, соответствующее переданному ключу key. Если ключа в массиве нет, то возвращается значение с типом V_UNDEF. TArray, если как аргумент был передан TArray, в этом случае каждому элементу key массива-аргумента будет соответствовать элемент value массива-результата, или элемент типа V_UNDEF, если ключ не найден.
var obj=TAssArraySI("январь",1,"февраль",2);
obj.Insert("сентябрь",9);
obj.InsertM("октябрь",10,"ноябрь",11);
PrintLn(obj.Get("октябрь")); //выведет 10
GetR(value)
Для классов семейства TBoostBiMap.
Возвращаемое значение:
Массив TArray ключей key, соответствующий переданному значению value. Если ключа в массиве нет, то возвращается пустой массив.
Массив массивов (TArray с элементами TArray), если как аргумент был передан TArray, в этом случае каждому элементу value массива-аргумента будет соответствовать массив ключей key массива-результата.
obj.Insert("ООО Ромашка","7701123458");
obj.Insert("Ромашка, ООО","7701123458");
obj.Insert("Общество с огр. отв. Ромашка","7701123458");
var a=obj.GetR("7701123458");
PrintLn(a[0]); // Общество с огр. отв. Ромашка
PrintLn(a[1]); // ООО Ромашка
PrintLn(a[2]); // Ромашка, ООО
Exist(key)
Проверяет, существует ли ключ в массиве.
Возвращаемое значение: true — если ключ есть в массиве, false — если ключа нет.
ExistR(key)
Для TBoostBiMap проверяет, существует ли значение в массиве.
Возвращаемое значение: true — если значение есть в массиве, false — если значения нет.
Del(key)
Удаляет из массива пару ключ-значение по переданному ключу.
Возвращаемое значение: true — если ключ был в массиве, false — если ключа не было.
At(key)
Свойство, допускающее присваивание. Позволяет прочитать или записать значение по переданному ключу. В режиме чтения аналогично Get.
Возвращаемое значение: value, соответствующее переданному ключу key. Если ключа в массиве нет, то возвращается значение с типом V_UNDEF.
obj.At("декабрь")=12;
PrintLn(obj.At("декабрь"));
Inc(key)
Увеличивает на единицу значение, соответствующее переданному ключу key. Если ключа в массиве не было, то он добавляется со значением 1. Рекомендуется для использования в счётчиках.
Возвращаемое значение: нет
Rewind
Смещает внутренний указатель на позицию перед началом. Применяется для организации цикла по всем элементам массива.
Возвращаемое значение: нет
Next
Смещает внутренний указатель на следующую позицию. Может применяется для организации цикла по всем элементам массива.
Возвращаемое значение: true — если конец массива не достигнут, false — если достигнут конец массива.
Prev
Смещает внутренний указатель на предыдущую позицию. Может применяется для организации цикла по всем элементам массива.
Возвращаемое значение: true — если конец массива не достигнут, false — если достигнут конец массива.
CurrentKey
Возвращает ключ, соответствующий позиции внутреннего указателя. Применяется для организации цикла по всем элементам массива.
Возвращаемое значение: key или значение с типом V_UNDEF, если достигнут конец массива.
CurrentValue
Возвращает значение, соответствующее позиции внутреннего указателя. Применяется для организации цикла по всем элементам массива.
Возвращаемое значение: value или значение с типом V_UNDEF, если достигнут конец массива.
GetGE([key])
Смещает внутренний указатель на позицию, ключ которой больше или равен key. Если аргумент опущен, то берётся key установленный предыдущим вызовом SetSeekKey.
Возвращаемое значение: true — если внутренний указатель успешно установлен в границах массива, false — если достигнут конец массива.
stat=obj.GetGE("Москва");
while (stat)
PrintLn(obj.CurrentKey,": ", obj.CurrentValue);
stat=obj.next
end;
GetGT([key])
Смещает внутренний указатель на позицию, ключ которой строго больше key. Если аргумент опущен, то берётся key установленный предыдущим вызовом SetSeekKey.
Возвращаемое значение: true — если внутренний указатель успешно установлен в границах массива, false — если достигнут конец массива.
GetLT([key])
Смещает внутренний указатель на позицию, ключ которой строго меньше key. Если аргумент опущен, то берётся key установленный предыдущим вызовом SetSeekKey.
Возвращаемое значение: true — если внутренний указатель успешно установлен в границах массива, false — если достигнут конец массива.
GetLE([key])
Смещает внутренний указатель на позицию, ключ которой меньше либо равен key. Если аргумент опущен, то берётся key установленный предыдущим вызовом SetSeekKey.
Возвращаемое значение: true — если внутренний указатель успешно установлен в границах массива, false — если достигнут конец массива.
GetEQ([key])
Смещает внутренний указатель на позицию, ключ которой равен key. Если аргумент опущен, то берётся key установленный предыдущим вызовом SetSeekKey.
Возвращаемое значение: true — если внутренний указатель успешно установлен в границах массива, false — если достигнут конец массива.
SetSeekKey(key)
Устанавливает ключ key, который будет использоваться GetGE, GetGT без аргумента.
Возвращаемое значение: нет
obj.SetSeekKey("Москва");
stat=obj.GetGE();
while (stat)
PrintLn(obj.CurrentKey,": ", obj.CurrentValue);
stat=obj.next
end;
KeyNum
Переключает режим поиска по ключу или по значению для функций GetGE, GetGT, GetLE, GetLT, GetEQ и SetSeekKey. 0 — искать по ключу, 1 — искать по значению.
Возвращаемое значение: нет.
/* пример. печать городов с количеством филиалов меньше 10 */
import "boostbmp.d32";
var obj=TBoostBiMapSI();
obj.InsertM("Москва", 20, "Ленинград", 10, "Екатеринбург", 5, "Нижний Новгород", 3, "Казань", 1);
obj.KeyNum=1; //следующие функции поиска будут работать по значению
obj.SetSeekKey(10);
var r=obj.GetLT();
while (r);
PrintLn(obj.CurrentKey," ",obj.CurrentValue);
r=obj.prev();
end;
Выведет:
Екатеринбург 5
Нижний Новгород 3
Казань 1
Delete
Удаляет из массива пару ключ-значение по ключу, ранее установленному SetSeekKey.
Возвращаемое значение: true — если ключ был в массиве, false — если ключа не было.
Implode([delim])
Собирает строку из значений.
delim — разделитель, строка, не обязательный аргумент, по умолчанию «, »
Возвращаемое значение: строка содержащая все значения в строковом представлении, разделённые разделителем.
ImplodeKV([delimV][, delimKV])
Собирает строку из ключей и значений.
delimV — разделитель пар ключ-значение, строка, не обязательный аргумент, по умолчанию «, »
delimKV — разделитель внутри пары ключ-значение, строка, не обязательный аргумент, по умолчанию «->»
Возвращаемое значение: строка содержащая все пары ключ-значение, разделённые разделителями.
Explode(str, [delimV][, delimKV])
Разбирает строку на пары ключ-значение и добавляет их в массив.
delimV — разделитель пар ключ-значение, строка, не обязательный аргумент, по умолчанию «;»
delimKV — разделитель внутри пары ключ-значение, строка, не обязательный аргумент, по умолчанию «,»
Возвращаемое значение: нет.
Set(key, value)
Устанавливает элемент массива с ключом key в значение value. Если ключа не было, он добавляется, если был, то его значение заменяется новым.
Возвращаемое значение: нет
Sum
Возвращаемое значение: сумма всех значений массива, для пустого — 0.
Size
Возвращаемое значение: количество элементов в массиве.
Empty
Проверка массива на пустоту. По классике этот метод предпочтительнее сравнения .Size==0.
Возвращаемое значение: true — если массив пустой, false — если есть элементы.
GetKeyArray
Возвращаемое значение: объект класса TArray, содержащий все ключи массива.
GetValueArray
Возвращаемое значение: объект класса TArray, содержащий все значения массива.
GetArray([array_key][, array_value])
array_key — если параметр задан и имеет класс TArray, то в нём буде возвращён массив, содержащий все ключи ассоциативного массива.
array_value — если параметр задан и имеет класс TArray, то в нём буде возвращён массив, содержащий все значения ассоциативного массива.
В теории работает быстрее, чем последовательный вызов GetKeyArray и GetValueArray, поскольку перебирает ассоциативный массив один раз.
Возвращаемое значение: нет.
Add(key, value)
Арифметически прибавляет value к значению, соответствующему ключу key. Если в масиве не было ключа key, то он добавляется и значение устанавливается в value.
key — ключ изменяемого значения.
value — прибавляемая величина или значение нового элемента.
Возвращаемое значение: нет.
Min([key])
Возвращает минимальное значение в массиве. Прямой перебор, на больших массивах может работать медленно.
key — если параметр задан, то в нём будет возвращён ключ, соответствующий возвращённому значению.
Возвращаемое значение: минимальное значение в массиве
Max([key])
Возвращает максимальное значение в массиве. Прямой перебор, на больших массивах может работать медленно.
key — если параметр задан, то в нём будет возвращён ключ, соответствующий возвращённому значению.
Возвращаемое значение: максимальное значение в массиве
First([key])
Возвращает первое значение в массиве.
key — если параметр задан, то в нём будет возвращён ключ, соответствующий возвращённому значению. Это будет минимальный ключ.
Возвращаемое значение: первое значение в массиве
Last([key])
Возвращает последнее значение в массиве.
key — если параметр задан, то в нём будет возвращён ключ, соответствующий возвращённому значению. Это будет максимальный ключ.
Возвращаемое значение: последнее значение в массиве
FldNumber
Эмулирует количество полей.
Возвращаемое значение: для TassArrayS — 1, для остальных — 2
NRecords
Аналог Size.
GetByNum(idx[, key])
Возвращает значение по порядковому номеру. Функция обладает низким быстродействием и служит исключительно для целей отладки.
idx — порядковый номер.
key — если параметр задан, то в нём будет возвращён ключ, соответствующий возвращённому значению.
Возвращаемое значение: последнее значение в массиве
ForEachMacro(macro_name)
Перебирает все элементы массива, и для каждого вызывает процедуру с именем macro_name. Процедуре передаётся два аргумента: ключ и значение. Перебор происходит в порядке возрастания ключа.
Возвращаемое значение: нет
var obj=TAssArraySI(
"010", 1,
"030", 3,
"050", 5);

macro Proc1(p1, p2)
PrintLn("Hello! I'm Proc1. My args: ", p1, ", ", p2);
end;

obj.ForEachMacro("Proc1");
ForEachDescMacro(macro_name)
Для TBoostBiMap. Перебирает все элементы массива, и для каждого вызывает процедуру с именем macro_name. Процедуре передаётся два аргумента: ключ и значение. Перебор происходит в порядке убывания ключа.
Возвращаемое значение: нет
ForEachMacroR(macro_name)
Для TBoostBiMap. Перебирает все элементы массива, и для каждого вызывает процедуру с именем macro_name. Процедуре передаётся два аргумента: ключ и значение. Перебор происходит в порядке возрастания значения.
Возвращаемое значение: нет
ForEachDescMacroR(macro_name)
Для TBoostBiMap. Перебирает все элементы массива, и для каждого вызывает процедуру с именем macro_name. Процедуре передаётся два аргумента: ключ и значение. Перебор происходит в порядке убывания значения.
Возвращаемое значение: нет
Write(file_name)
Записывает массив в файл. Впоследствии массив может быть прочитан методом Read.
file_name — строка, имя файла в который будет записан массив.
Возвращаемое значение: нет
Read(file_name)
Читает из файла массив, ранее записанный методом Write. Если файл не найден, будет сгенерированна ошибка.
file_name — строка, имя файла из которого будет прочитан массив.
Возвращаемое значение: нет
Copy()
Копирует объект в новый.
Возвращаемое значение: объект того же класса, содержащий копию
Конструктор
По поведению аналогичен InsertM.

Текст примера

 /* подсчёт встречаемости имён в базе субъектов */
import assarray;

var fPersn     =TBFile(  "persn.dbt",   "R", 0, null, "bank.def");
var obj=TAssArraySI(); /* key-value string-integer */

while (fPersn.next)
    obj.Inc(fPersn.rec.Name);
end;

PrintLn(obj.ImplodeKV("\n","\t")); //печать полученного результата


PrintLn("Наиболее распространённые имена: ");
var vmin=obj.min();
var vmax=obj.max();
var m=(vmax-vmin)/2+vmin;

obj.rewind();
while (obj.next)
    if (obj.CurrentValue>=m)
        PrintLn(obj.CurrentKey);
    end;
end;

/********************************************************************************/
/*                             Следующий пример                                 */
/********************************************************************************/
/* test-assa-pasp.mac */
/* демонстрация применения класса ассоциативного массива   */
/* и как он не справляется с задачей из-за нехватки памяти */
import "assarray.d32";

file p("..\\Import\\Fms\\list_of_expired_passports.csv") txt;
var s;
var obj=TAssArrayS();

//считывание файла в массив
PrintLn(Time());
while (next (p)) 
    obj.Insert(strsubst(p.str,",","")); //Здесь возникает исключение связанное с нехваткой памяти
end;
PrintLn(Time());


//проверка базы паспортов
var cntGood=0, cntBad=0;
var fRegDoc=TBFile("regdoc.dbt", "R", 2, null,"bank.def"); /* 2: RDKind, IsMail; 4: RDKind, Series, DocNum */ 
fRegDoc.rec.RDKind=0; //RD_KIND_PASSPORT
fRegDoc.rec.IsMail="X";
var okRegDoc=fRegDoc.GetGE();
while(okRegDoc and (fRegDoc.rec.RDKind==0) and (fRegDoc.rec.IsMail=="X"))
    if (obj.exist(fRegDoc.rec.Series +fRegDoc.rec.DocNum)) //составляем ключ и ищем его в массиве
        cntBad=cntBad+1;   //ключ найден - плохой паспорт
    else
        cntGood=cntGood+1; //ключ не найден - хороший паспорт
    end;
    okRegDoc=next;
end;
PrintLn(Time());

[Действительных   ######](cntGood);
[НеДействительных ######](cntBad);

/********************************************************************************/
/*                             Следующий пример                                 */
/********************************************************************************/
/* подсчёт статистики по счетам ПК. фрагменты макроса                           */
/* происходит сканирование операций и для каждого счёта накапливаются сумма     */
/* и количество операций определённых видов. используется массив структур       */
import "assarray.d32";
private var fAccount=TBFile("depositr.dbt","R", 8,null,"SBBANK.DEF"); 
private var fDoc = Tbfile("sbdepdoc.dbt", "R", 5, "sbdepdoc.dbt", "sbbank.def");

class AccInfo
    var Type_Account;
    var ClientId;

    var sumOut; //сумма расходных операций
    var cntOut; //кол-во расходных операций

    var sumOutPC; //сумма списаний через процессинг
    var cntOutPC; //кол-во списаний через процессинг

    var sumOutCom; //сумма операций комиссий
    var cntOutCom; //кол-во операций комиссий
end;

var a=TAssArraySO();
var objAccInfo;
…
    fDoc.rec.Date_Document=dlg.rec.dtbeg;
    var okDoc=fDoc.GetGE();
    while (okDoc and (fDoc.rec.Date_Document<dlg.rec.dtend))
        if (IsServStornDocWithEst(fDoc)) //не служебные операции
            fAccount.rec.Referenc=fDoc.rec.Referenc;
            if (fAccount.GetEQ)
                if (ФильтрПК())
                    if(a.exist(fAccount.rec.Account))
                        objAccInfo=a.Get(fAccount.rec.Account);
                    else
                        objAccInfo=GenObject("AccInfo");
                        
                        a.Insert(fAccount.rec.Account,objAccInfo);
                        objAccInfo.Type_Account=fAccount.rec.Type_Account;
                        objAccInfo.ClientId=fAccount.rec.CodClient;
                       
                        objAccInfo.sumOut=$0;
                        objAccInfo.cntOut=0;

                        objAccInfo.sumOutPC=$0;
                        objAccInfo.cntOutPC=0;

                        objAccInfo.sumOutCom=$0;
                        objAccInfo.cntOutCom=0;
                    end;

                    //Сумма расходных операций по счету
                    objAccInfo.sumOut=objAccInfo.sumOut+sumOutR;

                    //Кол-во Количество расходных операций по счету
                    objAccInfo.cntOut=objAccInfo.cntOut+1;

                    if (ФильтрПК_ПЦ())
                        objAccInfo.sumOutPC=objAccInfo.sumOutPC+sumOutR;
                        objAccInfo.cntOutPC=objAccInfo.cntOutPC+1;
                    end;
                    if (ФильтрПК_Комис())
                        objAccInfo.sumOutCom=objAccInfo.sumOutCom+sumOutR;
                        objAccInfo.cntOutCom=objAccInfo.cntOutCom+1;
                    end;
                end;
            else
                PrintLN("Не найден счёт по референсу "+fDoc.rec.Referenc+" "+fDoc.rec.Account);
            end;

        end;
        okDoc=fDoc.Next();
    end;

a.rewind; //устанавливаем "указатель" перед первым элементом
while(a.next) //цикл по всем элементам массива по возрастанию ключа
    rep.WriteRow(
        a.CurrentValue.Type_Account,   //a.CurrentValue это структура (класс) AccInfo
        GetClientCodeByID(a.CurrentValue.ClientId),
        a.CurrentKey,                  //a.CurrentKey это ключ, он же номер счёта

        a.CurrentValue.sumOut,
        a.CurrentValue.cntOut,

        a.CurrentValue.sumOutPC,
        a.CurrentValue.cntOutPC,

        a.CurrentValue.sumOutCom,
        a.CurrentValue.cntOutCom
        );
end;