insitudelL := (L::uneval, P::{set(posint), list(posint)}) → parse( "" || L || ":=[seq(`if`(member(`_0`," ( || convert(P, 'string')) || "),NULL," || L || "[`_0`]),`_0`=1..nops(" || || "))]:" 'L , statement') > H := [a,b,c,h,g,k,d,r,t,y,e]: insitudelL(H, {2,4,6,8,10}), H; ⇒ [a, c, g, d, t, e], [a, c, g, d, t, e] |
Реализованная однострочным экстракодом процедура insitudelL, обеспечивает удаление «на месте» элементов списка L, заданных списком/множеством их позиций Р [103,109].
В ряде задач работы со вложенными списками/множествами требуется определять элементы с максимальным/минимальным уровнем вложенности. Здесь может быть полезна процедура mlsnest. Вызов процедуры mlsnest(L) возвращает 2-элементный вложенный список, чей первый подсписок содержит номер элемента списка/множества L и минимальный уровнь его вложенности, тогда как второй подсписок определяет элемент L и максимальный уровнь его вложенности. При вызове mlsnest(L, 't') через t возвращается дополнительно множество всех уровней вложенности списка/множества L.
mlsnest := proc(L::{list, set}) local a n k j t r P N G, , , , , , , , ; `if` Empty(( L), RETURN(L), [ assign(n = [ ], t = 0, r = 0, N = [ ], a = whattype(L)), assign(G = convert(L, 'list'))]); for k to nops(G) do if not type(G k[ ], a) then n := [op(n), [k t, ]] else assign(' 't = 1, ' 'P = G k[ ]); do for j in P do if not type( ,j a) then next elif type ,(j a) and r = 0 then N := [op(N), op( )j ]; assign(' 't = t + 1, ' 'r = 16) else N := [op(N), op( )j ] end if end do; if r = 0 then assign(' 'n = [op(n), [k t, ]], ' 'N = [ ], ' 'r = 0, ' 't = 0); break else assign(' 'P = N, ' 'r = 0), assign(' 'N = [ ]) end if end do end if end do; assign(' 'r = SLj(n, 2)), [r[1], r[-1]], `if`(1 < nargs and type(args 2[ ], 'symbol'), assign('args'[2] = {seq(r[k][2], k = 1 .. nops(r))}), NULL) end proc > L:=[a,b,[x,[a,b],[c,b,x,y],[x,y]],c,[y,[a,b,[x,y,[2,z],z],[[8,16]]]],[[[[[a,b,c]]]]]]: mlsnest(L, 'z'), z; [[1, 0], [6, 5]], {0, 2, 4, 5} |
По вызову функции convert(B, 'set') можно конвертировать в структуру set-типа массив, таблицу или произвольное В-выражение, чьи операнды становятся элементами множества. При этом, операция конвертации список ⇒ множество ⇒ список в общем случае не является обратимой, хотя оба типа структур и базируются на общей последовательностной (exprseq) структуре.
Из рассмотренных выше средств по работе со списочными структурами кроме sort-функции остальные распространяются и на множества, не требуя дополнительных пояснений. Однако в случае необходимости любая функция, работающая со списочными структурами, может быть использована и с множествами, конвертировав их предварительно в списки. Этому способствует и то обстоятельства, что конвертация типа: множество ⇒ список ⇒ множество является обратимой, в отличие от конвертации типа: список ⇒ множество ⇒ список. Вместе с тем, структуры типа множество обеспечены Maple-языком рядом специальных функций для поддержки теоретико-множественных операций.
Для обеспечения работы с множествами Maple-язык пакета поддерживает три базовых теоретико-множественных оператора/функции, имеющих форматы кодирования:
M1 {union|intersect|minus} M2 {`union`|`intersect`|`minus`}(M1, M2, …, Mn)
и возвращающие соответственно результаты объединения (union), разности (minus) и пересечения (intersect) Mk-множеств (k = 1..n). Операторы {union, intersect} являются n-местными, инфиксными, ассоциативными и коммутативными, а minus - инфиксным бинарным оператором. Приведем простой пример на применение данных средств:
> `union`({a,b,c}, {x}), `intersect`({a,b,c}, {a,c}), `minus`({a,b,c}, {b}); ⇒ {a, b, c, x}, {a, c}, {a, c}
Рассмотренные в настоящем разделе средства Maple-языка для работы со списочными структурами и множествами будут в различных контекстах (глубже проясняющих их суть и назначение) использоваться при представлении разнообразных иллюстративных примеров. Между тем, следует иметь в виду, что наряду с рассмотренными пакет в рамках модульной части главной библиотеки предоставляет ряд функций по работе с рассмотренными структурами (списки и множества), поддерживаемых, в первую очередь, модулями combinat и totorder, позволяющими соответственно использовать комбинаторные операции со списками и упорядоченными множествами. Начиная с 7-го релиза, поставляется и модуль ListTools, содержащий набор средств для работы со списочными структурами. Его включение, по-видимому, было навеяно нашим набором средств подобного типа, созданных еще для Maple V (все наши издания по Maple-тематике хорошо известны разработчикам). Однако, не взирая на это, представленные в {103] средства работы со списками и множествами существенно дополняют имеющиеся средства пакета. Наконец, из-за пересечения свойств ряда типов структур, поддерживаемых пакетом, многие его функции в этом отношении многоаспектны, поэтому со списочными структурами и множествами допустимо использование и не только специфических для них средств.
Табличные объекты. Табличный объект (либо просто таблица) создается по встроенной функции table(F, L), где F – индексная функция и L – список/множество начальных входов таблицы. При этом, оба аргумента необязательны. Более того, создавать таблицу можно как явно по table-функции, так и неявно путем присвоения выражений индексированному идентификатору. В обоих случаях созданный объект опознается тестирующими средствами Maple-языка как таблица, например:
> T:= table([V=64, G=59, S=39, Art=17, Kr=10]): H[V]:=64: H[G]:=59: H[S]:=39: H[Art]:=17: H[Kr]:=10: map(type, [T, H], 'table'), map(typematch, [T, H], 'table'), map(hastype, [T, H],
'table'), map(whattype,map(eval, [T,H])); ⇒ [true, true], [true, true], [true, true], [table, table]
В отличие от массивов, у которых индексы должны быть целочисленны, входы (или индексы) таблицы могут быть любыми Maple-выражениями. Данное обстоятельство определяет важность и распространенность использования табличных объектов. В частности, в качестве входов таблицы могут выступать имена процедур, а выходов – соответствующие им определения. Ряд пакетных модулей организованы именно таким образом.
Функция table создает таблицу с начальными значениями, определяемыми L. Если L – список или множество уравнений, то левые части L становятся входами таблицы, а правые части ее выходами. В противном случае, элементы L становятся выходами таблицы, а входами становятся целые числа, начиная с 1. Использование множества начальных значений L в последнем случае неоднозначно, т.к. отсутствует порядок элементов множества, и следовательно порядок вхождений в результате может не соответствовать порядку, в котором вхождения были сделаны. Если аргумент L не определен, то создается пустая таблица, т.е. table([]). Новый вход в таблицу Т можно добавлять по конструкции T[Вход]:= <Выход>. По таким же конструкциям можно и создавать таблицу неявно. Удаление входов из таблицы Т можно выполнять по конструкции T[<Вход>]:= 'T[<Вход>]', например, Т[a]:= 'T[a]' удаляет из таблицы T элемент со входом a. При этом, обновление таблицы производится «на месте». Между тем, в ряде случаев более удобным является применение для этих целей нашей процедуры detab [103,108,109].
detab := proc(T::table, a::anything) local k; if nargs = 2 then table subs `if` type( ,( ( ( a {'set', 'list'}), [seq((a k[ ] = T[a k[ ]]) = NULL, k = 1 .. nops(a))], (a = T a[ ]) = NULL), op eval(( T)))) else assign('T' = table(subs(`if`(type(a, {'set', 'list'}), [seq((a k[ ] = T[a k[ ]]) = NULL, k = 1 .. nops(a))], (a = T a[ ]) = NULL), op eval(( T))))) end if end proc detab := proc(T::uneval, a::anything) local k; if type(eval(T), 'table') then if nargs = 2 then table subs `if` type( ,( ( ( a {'set', 'list'}), [seq((a k[ ] = T[a k[ ]]) = NULL, k = 1 .. nops(a))], (a = T[a]) = NULL), op(eval(T)))) else assign ' '( T = table subs `if` type( ,( ( ( a {'set', 'list'}), [seq((a k[ ] = T[a k[ ]]) = NULL, k = 1 .. nops(a))], (a = T a[ ]) = NULL), op(eval(T))))) end if else error "1st argument must has table-type but received %1-type"whattype(, eval(T)) end if end proc > T:= table([V=64, G=59, S=39, Art=17, Kr=10]): detab(T, {G, Art}), eval(T); table([V = 64, S = 39, Kr = 10]), table([V = 64, G = 59, S = 39, Art = 17, Kr = 10]) > detab(T, {G, Art}, 10), eval(T); ⇒ table([V = 64, S = 39, Kr = 10]) |
Достаточно простая процедура detab(T, a {, b}) возвращает результат удаления из таблицы Т элементов с входами, определенными вторым а-аргументом, в качестве которого может выступать как отдельный вход, так и их список/множество. В случае кодирования третьего необязательного аргумента (произвольное Maple-выражение) обновление таблицы Т удаляемыми элементами производится «на месте», т.е. обновляется сама исходная таблица Т. Выше представлены исходные тексты двух реализаций процедуры и некоторые примеры ее применения.
Замечание. Подход, реализованный в данной процедуре, может быть успешно применен в тех случаях, когда требуется вызовом процедуры обновлять вычисленные Maple-объекты, находящиеся вне тела самой процедуры, т.е. глобальные относительно ее и выступающие даже в качестве фактических аргументов. При этом, следует иметь в виду, что если в качестве обновляемых выступают объекты, не использующие специальных вычислительных правил подобно таблицам и процедурам (т.е. обращение к ним возвращает их идентификаторы, а не значения), то при указании их в качестве формального аргумента им следует присваивать uneval-тип. Второй способ реализации detab-процедуры иллюстрирует вышесказанное. Между тем, операцию обновления «на месте» следует выполнять довольно осмотрительно во избежание возможной рассинхронизации вычислительного процесса в целом.
Функция индексации F может быть процедурой или идентификатором, определяющим каким образом должна выполняться индексация; по умолчанию полагается обычная индексация. В качестве встроенных функций индексации пакет допускает: symmetric, antisymmetric, sparse, diagonal и identity. Для дополнительной информации об этих функциях см. ?indexfcn.