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

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

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

Описание

Класс для 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;