• Таблица (table) – структура данных, весьма широко используемая Maple, прежде всего, при работе с различного рода табличными объектами. Таблица представляет собой определенное обобщение понятия двумерного массива, когда в качестве значений индексов массива могут использоваться не только целочисленные значения, но и произвольные выражения, в первую очередь, символьные и строчные значения в качестве названия строк и столбцов. Характерной чертой таблицы является возможность работы со структурами данных, включающими естественные нотации (фамилии, имена, названия и т.д.). Итак, в общем случае Т-таблица определяется конструкцией следующего простого формата:
T := table(<Индексная функция>, <Список/множество начальных значений>) где Индексная функция определяет специальный индексный атрибут (например, symmetricатрибут), аналогичный случаю массива, и второй аргумент определяет исходные значения для элементов таблицы (ее входы и выходы). Пустая таблица определяется по конструкции вида T:= table(); при этом, первый аргумент table-функции необязателен.
Второй аргумент table-функции определяется, как правило, в виде списка или множества, элементами которого могут быть как отдельные допустимые Maple-выражения, так и уравнения, т.е. конструкции вида “A=B”. Левые А-части уравнений выступают в качестве идентификаторов строк таблицы и определяют ее входы, а правые – выходы, т. е. по конструкции формата T[<Вход>] возвращается строка-выход, отвечающая указанному в качестве значения аргумента Входу. Поэтому, если T:=table([X1=Y1, X2=Y2, ...]), то T[Xk]; ⇒ Yk. Если в списке/множестве начальных значений хоть один из элементов не является уравнением, то Maple в качестве входов в таблицу использует целые неотрицательные числа (1 .. <число строк>), располагая при этом строки таблицы в определенном порядке, отличном от естественного. Это одна из причин, почему в качестве элементов второго аргумента функции table следует кодировать уравнения, т.е. это не тот случай, когда решение вопроса стоит отдавать на откуп пакету. В качестве правых В-частей уравнений списка/множества функции могут выступать произвольные Maple объекты, позволяя создавать достаточно сложные табличные структуры данных, примером чего может служить следующий весьма простой фрагмент:
> T:= table([A=[AV, 42, 64, 350], B=[42, 64, array([[RANS, IAN], [REA, RAC]])],
C=array([[{G, S}, {Kr, Ar}], [{Vasco}, {Salcombe}]])]): eval(T);
table([C = {{VascoS, G}} {Salcombe{Kr, Ar} }, B = 42 64, , RANSREA A = [AV, 42 64 350, , ] ]) | IAN, RAC |
При этом, более простым способом создания таблицы является непосредственное присвоение индексированной переменной значений, как это иллюстрирует следующий весьма простой фрагмент:
> Tab[Grodno]:= 1962: Tab[Tartu]:= 1966: Tab[Tallinn]:= 1999: Tab[Gomel]:= 1995: Tab[Moscow]:= 1994: eval(Tab), print(Tab); table([Grodno = 1962, Tartu = 1966, Tallinn = 1999, Gomel = 1995, Moscow = 2006]) table([Grodno = 1962, Tartu = 1966, Tallinn = 1999, Gomel = 1995, Moscow = 2006]) > (Tab[Grodno]-Tab[Tallinn]-Tab[Moscow])/(Tab[Tartu]-Tab[Gomel]-350); ⇒ 2043/379 > Tab[Grodno], Tab[Tartu], Tab[Tallinn], Tab[Gomel], Tab[Moscow]; 1962, 1966, 1999, 1995, 2006 > whattype(Tab), whattype(eval(Tab)), type(Tab, 'table'), type(eval(Tab), 'table'), map2(type, Tab, ['matrix', 'array']); ⇒ symbol, table, true, true, [false, false] > op(0, eval(Tab)), [op(1, eval(Tab))], op(2, eval(Tab)); table, [], [Grodno = 1962, Tartu = 1966, Tallinn = 1999, Gomel = 1995, Moscow = 2006] |
Обращение к таблице производится по ее идентификатору, а к ее элементам в форме индексированного идентификатора, например: Т[С]. Вывод таблицы на печать производится по функции print (применение которой проиллюстрировано выше); это же относится и к выводу ее отдельных выходов, если они не являются конструкциями базовых типов {число, строка, список, множество}. При этом, подобно массиву таблица одновременно выводится и возвращается по функции eval, тогда как к ней не применимы функции evalm и evala. Приведенный выше фрагмент иллюстрирует сказанное. Наряду с этим, примеры фрагмента иллюстрируют использование op-функции для получения типа Tab-объекта, индексной функции (первый аргумент table-функции) и содержимого всех входов таблицы. По причине отсутствия индексной функции вызов op(1, eval(Tab)) возвращает NULL-значение.
Наиболее простой формат table-функции имеет следующий вид:
T := table([X1, X2, X3, ..., Xn]) или T := table({X1, X2, X3, ..., Xn})
определяя Т-таблицу из n строк, идентифицируемых входами-числами. Переопределение элементов Т-таблицы производится по конструкциям вида: Т[<вход>]:=<Выражение>, которые работают и со списочными структурами. Для удаления из Т-таблицы выхода (соответствующего заданному входу) выполняется следующая конструкция: Т[вход]:=NULL, тогда как для удаления всех выходов произвольной Т-таблицы достаточно выполнить следующее простое Maple-предложение цикла:
for k in [<Список входов>] do T[k]:= NULL end do:
либо эквивалентное ему выражение следующего вида:
eval(parse(convert(subs(F = null, mapTab(F, T, 1)), 'string')))
где null и mapTab – процедуры из Библиотеки, описание которых находится в [103]:
> Tab[Grodno]:= 1962: Tab[Tartu]:= 1966: Tab[Tallinn]:= 1999: Tab[Gomel]:= 1995: Tab[Moscow]:= 2006: eval(parse(convert(subs(F = null, mapTab(F, Tab, 1)), 'string'))); table([Tartu = (), Tallinn = (), Gomel = (), Moscow = (), Grodno = ()])
При работе с массивами и таблицами наиболее часто используемыми являются две функции indices и entries, имеющие следующий простой формат кодирования; {indices|entries}(T), где Т – массив или таблица
и возвращающие индексы/входы и соответствующие им элементы/выходы массива/таблицы Т соответственно, как это иллюстрирует следующий простой фрагмент:
> Tab[Grodno]:= 1962: Tab[Tartu]:= 1966: Tab[Tallinn]:= 1999: Tab[Gomel]:= 1995:
Tab[Moscow]:= 2006: indices(Tab), entries(Tab);
[Tartu], [Tallinn], [Gomel], [Moscow], [Grodno], [1966], [1999], [1995], [2006], [1962]
> A:= array([[a, b, h], [c, d, k], [x, y, z]]): indices(A), entries(A);
[1, 1], [2, 2], [2, 3], [2, 1], [3, 1], [3, 2], [1, 2], [1, 3], [3, 3], [a], [d], [k], [c], [x], [y], [b], [h], [z]
> with(Tab); eval(%);
[Gomel, Grodno, Moscow, Tallinn, Tartu]
[1995, 1962, 2006, 1999, 1966]
> Tab1[1942]:= 1962: Tab1[2006]:= 1966: type(Tab1, 'table'); with(Tab1); ⇒ true Error, (in pacman:-pexports) invalid arguments to sort
> map(op, [indices(Tab)]), map(op, [entries(Tab)]);
[Tartu, Tallinn, Gomel, Moscow, Grodno], [1966, 1999, 1995, 2006, 1962]
В частности, последний пример фрагмента представляет конструкции, полезные при работе, прежде всего, с таблицами, и позволяющие представлять их входы и выходы в виде списка. Во фрагменте (пример 3) проиллюстрировано также использование процедуры with (применяемой, как правило, лишь с пакетными и программными модулями) для получения списка входов таблицы. При этом, следует учитывать, что если в качестве входов Т-таблицы выступают значения {symbol|name}-типа, то по выхову with(T) возвращается их отсортированный лексикографически список, в противном случае возникает ошибочная ситуация, как это иллюстрирует пример 4 предыдущего фрагмента.
Имея многочисленные приложения, табличные структуры используются и для организации пакетных и/или библиотечных модулей. Такой подход особенно широко использовался в ранних релизах пакета и об этом детальнее будет сказано ниже. Представим здесь один простой пример такого подхода. В этом случае входами таблицы Т являются имена процедур, а ее выходами – соответствующие им определения. Тогда вызов таким образом погруженных в табличную структуру процедур принимают следующий простой вид, а именно: Т[имя](Аргументы). Следующий фрагмент иллюстрирует сказанное:
> T:= table([sr = (() -> `+`(args)/nargs), (ds = (() -> sqrt(sum((args[k] - sr(args))^2, k=1..nargs)/nargs)))]); ( ) T sr nargs ds ( ) → nargsk∑ = 1 (argsnargsk − sr args( ))2 ]) := table([ = ( ) → `+` args , = > with(T), 6*T[sr](64,59,10,17,39,44), 6*T[ds](64,59,10,17,39,44); ⇒ [ds sr, ], 233, 14249 > save(T,"C:\Temp\lib.m"); restart; read("C:\Temp\lib.m"); with(T); ⇒ [ds, sr] > 6*T[sr](64,59,10,17,39,44), 6*T[ds](64,59,10,17,39,44); ⇒ 233, 14249 |
Данный подход эффективен, например, когда требуется создавать средства модуля пакета табличного типа поэтапно – экспорты (входы таблицы). В этом случае одноименные входы заменяют соответствующие им выходы, тогда как новые входы просто добавляются в таблицу. Данный подход имеет и другие привлекательные особенности.
Относительно структур типа массив (array) и таблица (table) следует сделать одно существенное пояснение. Все используемые Maple структуры, кроме этих двух, обладают свойством ненаследования, т.е. для них справедливы следующие соотношения:
X:= a: Y:= X: Y:= b: [X, Y]; ⇒ [a, b]
т.е. присвоение X-значения Y-значению с последующим переопределением второго не изменяет исходного X-значения. В случае же структур типа массив и таблица это вполне естественное свойство не соблюдается. Поэтому Maple-язык располагает специальной процедурой copy(<Массив/Таблица>), позволяющей создавать копии указанного массива/таблицы, модификация которой не затрагивает самого оригинала. Следующий весьма простой фрагмент иллюстрирует вышесказанное: