Delphi programming blog
Источник: http://teran.karelia.pro/articles/item_4411.html
 

диапазоны номеров и множества.

Опубликовано 05.04.2010 г. 15:24
недавно озадачился на работе проблемой. допустим имеется строка 1,2,5-7,10 и требуется некоторый список целочисленных значений для заданного строкового диапазона. В моем случае значения ограничены, и максимальное значение принимает значение 100. поэтому для данных целей весьма удобно было использовать множества (ибо размерность множества ограничена 256 значениями), хотя как вариант, можно сформировать массив целых чисел. Итак задача такова: преобразовать строковую запись "1,2,5-7,10" в множество [1,2,5..7,10]. В действительности номера данные обозначают коды регионов, поэтому определим тип данных
    TRegionListSet = set of byte;
и для преобразования строки во множество определим функцию
function ExportGetRegionList(str:string):TRegionListSet;
для разбиения значений с использованием запятых воспользуемся классом TStringList, хотя, конечно, можно было это сделать и руками. Собственно нам потребуется один sl:TStringList для хранения разделенных значений, а также в случае указания интервала вида "5-7", нам потребуется найти позицию дефиса Р, а также стартовое и конечное значение интервала s & e. Все что требуется сделать это передать в TStringList значения нашей исходной строки, разбить ее с использованием разделителя запятой, для каждого значения проверить является ли оно просто значением, или содержит интервал значений, и добавить соответствующее значение/интервал к результирующему множеству.
function ExportGetRegionList(const str:string):TRegionListSet;
var sl : TStringList;
    s,e : byte;
    p:integer;
begin
    result := [];
    try
        sl := TStringList.Create();
        sl.CommaText := str;

        for str in sl do  begin
            p := pos('-',str);
            if  p  0 then begin
                s := StrToInt(copy(str,1,p-1));
                e := StrToInt(copy(str, p+1, length(str) - p));
                result := result  + [s..e];
            end
            else result := result + [ StrToInt(str) ];
        end;
        sl.Free;
    except
        MessageDlg('Указан некорректный диапазон регионов.',mtError,[mbOk],0);
        if assigned(sl) then
            freeAndNil(sl);
    end;
end;
единственная неприятность которую я недавно заметил при использовании множеств такова: При написании цикла
for i in [3,4] do ..
выполняется две итерации для значений i=3 & 4. А вот если множество представляет собой переменную, то цикл
var s : set of byte;
s := [3,4];
for i  in s do ...
эквивалентен конструкции
for i:=0 to 255 do begin
    if i in [3,4] then do ..
end;
странно как то.
Метки:  sets  |  множества 

Комментарии

Дож
15.04.2010 в 11:39
> странно как то.

А как иначе? Нужно пробежать по всем элементам множества и каждый проверить на включение. Нет возможности, например, получить элементы в виде массива.

С константным множеством все проще, потому что можно развернуть код во что-то вида
i := 3;
do;
i := 4;
do;
ter
16.04.2010 в 00:53
о их в цикл преобразует, т.е полностью код не разворачивает. для константных в смысле.
- Имя
- e-mail*
- Сайт
вы можете использовать теги [i],[b],[code],[quote]
Дополнительно