Цель лекции: познакомиться с одним из основных классов данных Mathematica — списками, познакомиться с принципами работы с ними
Значительная доля вычислений так или иначе связана не с отдельными выражениями, а с целыми массивами тем или иным образом сгруппированных данных. Именно поэтому для работы с такими данными в Mathematica существует целый класс данных, называемый списками. Как мы помним из предыдущей лекции, список представляет собой удобную форму структурирования данных, по строению представляет собой множество элементов, заключённых в фигурные скобки { } и разделённых запятыми: {expr1,expr2,...}. Для каждой открывающей фигурной скобки { в списке должна присутствовать закрывающая фигурная скобка }. Элементами списка могут быть любые выражения: числа, символы, строки, функции, графические изображения, а также другие списки. Для работы со списками в Mathematica имеется широчайший набор инструментов: можно различными способами создавать списки, преобразовывать их, а также извлекать информацию из уже имеющихся списков. Для знакомства с указанными возможностями
воспользуемся логикой изложения материала в работе П. Веллина и др. [14].
В Mathematica список есть выражение, имеющее заголовок List, поэтому наиболее естественный для Mathematica способ задания списка — в виде List[element1,element2,...], где element1,element2,... — элементы списка (пример In[1] на рис. 3.1). С более простым и наглядным для пользователя способом задания списка мы уже познакомились в предыдущей лекции: он заключается в том, чтобы ввести через запятую элементы списка и обособить их фигурными скобками (пример In[2]).
Если список включает в себя только числа одного из трёх типов: целые, рациональные или вещественные — и элементы списка подчиняются какой-либо периодической закономерности, то задать список можно, воспользовавшись функцией Range[imin,imax,di]. В результате генерируется список от наименьшего значения imin с приращением (разностью между соседними элементами) di до значения меньшего или равного imax.
В примере In[3] на рис. 3.1 мы создаём список целых чисел, начиная от числа 2. Последующие элементы получаются добавлением к текущему элементу числа 3. Наибольшее значение элемента списка не будет превышать числа 19.
Если приращение di равняется единице, можно воспользоваться упрощённой версией функции — Range[imin,imax]. Так в примере In[4] на рис. 3.1 мы задаём список вещественных чисел, начиняя от числа 1.5. Поскольку приращение не задано, последующие элементы генерируются прибавлением к предыдущим элементам единицы. Наибольшее значение элемента списка не будет превышать числа 8.
Существует ещё более простая версия функции — Range[imax], которая задаёт ряд натуральных чисел от 1 до значения меньшего или равного imax: это может понадобиться, например, в случае, когда требуется задать нумерацию. Так в примере In[5] на рис. 3.1 мы генерируем ряд натуральных чисел от 1 до 10.
Подробней о функции Range см. книги Е. М. Воробьёва [1, с. 101, 161] и П. Веллина и др. [14, с. 55–56].
(рис 3.1) Простейшие способы задания списков
Mathematica позволяет задавать и более сложно устроенные списки числовых данных. Для этого используется функция Table. В наиболее полной своей форме функция выглядит следующим образом: Table[expr,{i,imin,imax,di}]. Первый аргумент функции, expr, представляет собой выражение, которое вычисляется в процессе построения списка, и вычисленное значение включается в список как один из его элементов. Второй аргумент функции, {i,imin,imax,di}, называется итератором (iterator). В случае Mathematica итератор можно рассматривать как объект, указывающий на расположенные определённым образом элементы в наборе данных. Итератор представляет собой перечень параметров, определяющих в конечном итоге число элементов списка. Параметры могут также входить в выражение expr в качестве констант или переменных. Параметр imin принимает численные значения и определяет первое значение переменного параметра i, приращение di — величина,
использующаяся для задания последующих элементов списка, число imax определяет наибольшее возможное значение i: если при возрастании значения i с интервалом di получается величина, превышающая imax, то построение списка заканчивается, а полученное значение при этом не используется.
В примере In[1] на рис. 3.2. при помощи функции Table мы задаём список элементов, удовлетворяющих выражению 2*k, причём k меняется от 1.1 до 15 с интервалом 2.
При помощи функции Table[i,{i,imin,imax,di}] можно продублировать уже известную нам функцию Range[imin,imax,di] (пример In[2] на рис. 3.2: ср. списки, полученные в Out[2]). И точно так же функцию Table можно записывать в упрощённом виде: Table[expr,{i,imin,imax}] — когда приращение равно единице, Table[expr,{i,imax}] — когда равны единице приращение di и первое значение переменного параметра i (соответствующие примеры In[4] и In[5]).
Если выражение expr не зависит от переменного параметра, то функцию можно записать как Table[expr,{imax}]: она генерирует ряд, содержащий число элементов, равное целой части выражения imax, причём каждый элемент содержит выражение expr. Однако здесь с подачи Е. М. Воробьёва [1, с. 101–102] необходимо сделать уточнение. Дело в том, что одно и то же исходное выражение expr в ряде случаев при вычислении может давать различные результаты. Для понимания этого неожиданного заявления рассмотрим функцию Random, часто используемую в математическом моделировании. Выражение Random[] в качестве результата вычисления возвращает однородно распределенную псевдослучайную вещественную величину, заключенную в интервале от 0 до 1. Поэтому выражения Table[Random[],{imax}] генерирует ряд случайных чисел со значением от 0 до 1, состоящий из imax числа элементов — см. пример
In[6] на рис. 3.2.
Скажем ещё несколько слов о функции Random. Выражение Random[type,{imin,imax}] задаёт случайное число, принадлежащее интервалу {imin,imax} и относящееся к типу type, где type принимает значения типов чисел, Integer, Real или Complex. В случае типа Real третий аргумент функции Random может задавать число цифр, используемых при задании вещественного числа.
Подробней о функции Random см. книгу Е. М. Воробьёва [1, с. 101–102].
В примере In[7] на рис. 3.2. мы генерируем целое число, принадлежащее промежутку от 5 до 101, а в In[8] — вещественное число из промежутка от 3.5 до 7.1, причём представляем его с точностью до пятнадцати значащих цифр.
(рис 3.2) Задание списков при помощи функции Table
Функция Table также позволяет генерировать вложенные списки, то есть, списки, элементами которых являются другие списки. Списки, являющиеся элементами вложенного списка, называются внутренними. Это делается путём добавления в функцию ещё одного итератора — пример In[1] на рис. 3.3. Когда функция содержит больше одного итератора, порядок итераторов оказывается существенным, поскольку значения внешнего итератора различны для каждого значения внутреннего итератора. В нашем примере In[1] для каждого значения j (внутренний итератор) параметр i (внешний итератор) изменяется от 1 до 3, при этом создаётся список из четырех элементов, каждый из которых содержит ещё по 3 элемента. Если мы поменяем в выражении In[1] порядок итераторов, то получим список из трех элементов, каждый из которых содержит по четыре элемента — пример In[2].
Подробней о функции Table см. книги Е. М. Воробьёва [1, с. 101–103] и П. Веллина и др. [14, с. 56–58].
(рис 3.3) Задание вложенных списков
Теперь разберёмся в терминологии. В предыдущих лекциях мы уже встречались понятием многоуровневости. Мы говорили о том, что любое выражение во внутреннем представлении являет собой многоуровневую структуру: на нулевом уровне содержится заголовок выражения, на первом — аргументы функции, определяемой заголовком, на втором — аргументы аргументов и так далее. Количество уровней внутренней формы соответствует максимальному номеру уровня в выражении плюс единица, то есть, в него входит и нулевой уровень.
Когда мы говорим о числе уровней списков, мы имеем в виду только те уровни, на которых содержатся элементы списков. Это значит, что ни о каком нулевом уровне списков речи не идёт, и, соответственно, количество уровней списка соответствует максимальному номеру уровня. Здесь также следует отметить, что заголовок списка List является нулевым элементом (но не уровнем!) списка, который он определяет.
Чтобы окончательно запутать читателей, отметим ещё следующее: список, как и всякое выражение, может быть представлен в полной форме. В этом случае следует заранее оговаривать, об уровнях списка или уровнях полной формы представления списка идёт речь.
Вложенные списки можно представлять на экране различными способами. С простейшим, "одноэтажным" способом мы уже подробным образом познакомились. Однако такое представление не является достаточно наглядным. Гораздо удобней выводить списки на экран в виде таблицы — функцией TableForm, и матрицы — функцией MatrixForm — см. соответствующие примеры In[1] и In[2] на рис. 3.4. Дополнительная опция TableHeads функции TableForm добавляет заголовки столбцам и строкам таблицы (пример In[3]).
Внешний итератор может зависеть от значения внутреннего итератора (П. Веллин и др. [14, с. 57]), в результате чего могут создаваться непрямоугольные списки — см. пример In[4] на рис. 3.4, в котором количество столбцов в таблице меняется с изменением номера строки. Но внутренний итератор зависеть от внешнего не может, поскольку, как мы видели выше, при генерации списка внутренний итератор должен иметь фиксированное значение, пока изменяется внешний.
(рис 3.4) Способы представления списков при помощи функций TableForm и MatrixForm
В Mathematica имеется функция DiagonalMatrix[list], позволяющая из заданного списка list порождать новый список, отвечающий диагональной матрице с элементами списка list на главной диагонали. Также имеется функция IdentityMatrix[n], порождающая единичную матрицу размерности n x n. Примеры задания таких матриц см. на рис. 3.5.
(рис 3.5) Задание диагональных матриц
Последним способом задания списков, с которым мы познакомимся в рамках данного курса, является использование функции с заголовком Array. Функция Array[a,n] порождает список длины п с элементами а[i], где i=1,2,...,n. Итератор, заданный в виде {n1,n2,...}, приводит к созданию вложенного списка — см. пример In[1]. Функция Array[a,it,origin] дает список, в котором индексы итераторов it изменяются, начиная со значения origin, по умолчанию равного единице (пример In[2]). Если же функция задана в полной форме, Array[а,it,origin,h], то получается выражение, в котором заголовок List всюду заменен заголовком h — пример In[3] на рис. 3.6.
Подробней о функции Array см. книгу Е. М. Воробьёва [1, с. 103].
(рис 3.6) Использование функции Array для задания списков
Списки относятся к данным сложной структуры. Поэтому при работе с ними возникает необходимость контроля над структурой, иначе применение списков может привести к грубым ошибкам, как явным, сопровождаемым выдачей сообщения об ошибке, так и неявным, на наличие которых Mathematica никаким образом не реагирует, но результаты расчётов оказываются неверными. Для выявления структуры списков в программе имеется ряд функций. Одна из них — Length. Она возвращает длину списка — число элементов списка. Если мы применим эту функцию к линейному (невложенному, не содержащему в качестве элементов других списков) списку, то мы получим число элементов, которое в нём содержится; для вложенных списков мы получим число внутренних списков в нём, при этом количество элементов в этих внутренних списках приниматься в расчёт не будет — см., соответственно, примеры In[1] и In[2] на рис. 3.7.
Если вложенный список полностью состоит из внутренних списков одинаковой длины, то всё-таки существует возможность получить информацию о длине внутренних списков: для этого следует воспользоваться функцией Dimensions. При помощи этой функции в примере In[3] на рис. 3.7 мы узнаём о том, что заданный список содержит два внутренних списка, каждый из которых сам состоит из трёх списков, содержащих по два элемента. Помогает нам функция Dimensions и в экзотическом случае, когда на каждом уровне вложенного списка содержится всего один элемент — пример In[4].
Если вложенный список list состоит из внутренних списков одинаковой длины только до определённого уровня n, то функция Dimensions поможет узнать структуру list только до этого уровня n включительно. Например, в трёхуровневом списке {{a,b},{c,{d,e}} на первом уровне находится два элемента, представляющих собой списки {a,b} и {c,{d,e}}. Каждый элемент-список также содержит по два элемента, которые являются элементами второго уровня: в первом случае — это символы a и b, а во втором — символ c и список {d,e}. На третьем уровне находятся только элементы списка {d,e}, очевидно, что символы a, b и c никаких элементов не содержат. Таким образом, для исходного списка количество элементов внутренних списков совпадает только до второго уровня включительно, и также до второго уровня этот список может быть описан функцией
Dimensions. Таким образом, вычисление выражения Dimensions[{{a,b},{c,{d,e}}] вернёт в выходной ячейке Out выражение {2,2}. Справедливость наших рассуждений подтверждается примером In[5] на рис. 3.7.
Если вложенный список состоит из списков одинаковой длины, то для того, чтобы определить глубину этого вложенного списка, то есть, число уровней, на которое необходимо спуститься, чтобы добраться до выражения, не являющегося списком, используется функция ArrayDepth — пример In[6] на рис. 3.7.
Подробней о получении информации о длине и глубине списков см. книгу П. Веллина и др. [14, с. 58–59].
(рис 3.7) Определение структуры линейных и вложенных списков
Если список expr является тензором, то функция TensorRank[expr] позволяет определить ранг этого тензора — рис. 3.8.
(рис 3.8) Определение ранга тензора
Крайне полезной в Mathematica является возможность проверять списки на содержание тех или иных выражений. Так функция FreeQ[list,form] возвращает True, если список list НЕ содержит выражения form; также в пакете имеется в некоторой мере дублирующая функция MemberQ[list,form], которая напротив возвращает True, если список list содержит выражение form (см. примеры In[1], In[2] и In[3] на рис. 3.9). А функция Position[list,form] возвращает позицию искомого элемента form в списке list. В нашем примере In[4] буква c занимает позицию с номером 3. Если список list не содержит выражения form, то возвращается пустой список {}.
Эта же функция поможет нам, если мы хотим узнать позицию того или иного выражения во вложенном списке. Отличие будет лишь в представлении результата. В примере In[5] на рис. 3.9 буква h занимает позицию под номером 2 в третьем элементе вложенного списка.
Узнать, сколько раз некоторый элемент elem встречается в списке list, можно с помощью функции Count[list,elem]. Если список list не содержит выражения elem, то Count возвращает 0. Так в примере In[6] на рис. 3.9 мы выяснили, что символ b содержится в заданном списке 3 раза.
(рис 3.9) Проверка списка на содержание в нём заданных выражений
Ещё одна функция Select[list,cond] позволяет выбирать элементы списка list, возвращающие True при применении к ним предиката cond. В примере In[1] на рис. 3.10 из списка выбираются только чётные числа.
Для того чтобы выбрать из списка list только одинаковые элементы elem, недостаточно просто указать elem вместо условия cond: в этом случае будет просто сгенерирован пустой список (см. пример In[2] на рис. 3.10). Для этого следует задать условие с использованием анонимной функции в виде #==elem. Так в примере In[3] мы выбираем из исходного списка только двойки. С анонимными функциями мы подробней познакомимся в лекции 9 настоящего курса, посвящённой функциональному программированию.
Если условию cond не соответствует ни один элемент списка list, то Select[list,cond] генерирует пустой список.
Подробней о функциях проверки содержания списка см. книгу П. Веллина и др. [14, с. 60–61].
(рис 3.10) Выбор элементов списка по условию
При помощи функции Part[list,n] можно извлечь из списка list элемент, зная его позицию n в списке. Эту функцию также можно задать в сокращённом виде, используя двойные скобки: list[[n]]. Чтобы обратиться сразу к нескольким элементам списка, следует задать функцию в виде Part[list,{n1,n2,...}] или list[[{n1,n2,...}]], где n1,n2,... — номера элементов, которые требуется извлечь.
В примере In[1] на рис. 3.11 мы задали одноуровневый список list, в In[2] при помощи полной формы функции Part мы извлекли второй элемент списка list, а в In[3], — используя сокращённую форму, третий и пятый элементы.
(рис 3.11) Извлечение элементов линейных списков
Для того чтобы извлечь элемент из вложенного списка, необходимо указать и номер подсписка, в котором находится необходимый элемент, и номер элемента в этом подсписке. На рис. 3.12 приведён пример извлечения элементов матрицы 3х3. В примере In[2] мы извлекаем элемент с номером 2 из третьего подсписка. В примере In[3] мы полностью извлекаем второй столбец матрицы, заменив номер подсписка на выражение All, а в примере In[4] — третью строку, которая также является третьим подсписком исходного списка, причём мы можем либо заменить номер элемента на All, либо вовсе опустить этот параметр.
(рис 3.12) Извлечение элементов вложенных списков
Для обращения к элементам списка в Mathematica имеется ещё одна функция — с заголовком Take. В своей простейшей форме Take[list,{b1,b2}] она возвращает фрагмент списка list, содержащий элементы с номерами от b1 до b2, причём если b1, b2 принимают положительные значения, то номер элемента отсчитывается от первого (пример In[1] на рис. 3.13), а если отрицательные — от последнего (пример In[2]). При этом b1 и b2 могут принимать положительные и отрицательные значения независимо друг от друга (пример In[3]).
Если функция задаётся в виде b — от элемента с номером абсолютного значения b с конца списка до последнего элемента в списке (примеры In[4] и In[5] на рис. 3.13).
В наиболее полной форме Take[list,{b1,b2,di}] функция из списка list выбирает каждый di-й элемент, начиная с элемента под номером b1 и заканчивая элементом с номером, не большим, чем b2 (пример In[6] на рис. 3.13).
Подробней об управлении содержанием списка см. книги Е. М. Воробьёва [1, с. 105–106] и П. Веллина и др. [14, с. 62–63].
(рис 3.13) Использование функции Take для извлечения фрагментов списков
Mathematica позволяет отбрасывать фрагменты списка при помощи функции Drop[list,bound], где bound задаёт фрагмент списка list, который необходимо отбросить. Правила задания функции Drop такие же, как и для Take. Примеры отбрасывания элементов в начале, конце и в произвольном месте списка представлены на рис. 3.14 как In[1], In[2] и In[3], соответственно.
Помимо отбрасывания целых фрагментов Mathematica позволяет селективно удалять элементы списка с определёнными номерами при помощи функции Delete[list,{{n1},{n2},...}], где n1,n2,...— номера элементов списка list, которые необходимо удалить — примеры In[4] и In[5] на рис. 3.14.
(рис 3.14) Удаление элементов списка
Mathematica позволяет добавлять в списки новые элементы. Для добавления элементов в начало и конец списка имеются соответствующие функции: Prepend[list,n] и Append[list,elem] (см. примеры In[1] и In[2] на рис. 3.15).
Функция Insert[list,elem,n] помещает выражение elem на позицию n в списке list, причём число n может принимать как положительные, так и отрицательные значения (пример In[3] на рис. 3.15).
Как мы уже отмечали, элементами списка могут быть любые выражения, в том числе и списки. Новый элемент elem можно вставить в любой внутренний список в списке list или внутрь любого элемента списка, если этот элемент не является атомарным выражением. В примере In[4] на рис. 3.15 указание позиции в виде {1,2} означает, что новый элемент нужно вставить в первый элемент списка на вторую позицию. Один и тот же элемент можно вставить на несколько позиций — см. пример In[5].
Mathematica позволяет осуществлять суперпозицию описанных выше функций удаления и добавления элементов в список — заменять один элемент другим. Делается это при помощи функции ReplaceRart[list,elem,n], которая заменяет элемент списка list под номером n элементом elem — см. пример In[6] на рис. 3.15.
(рис 3.15) Добавление элементов в список
Элементы списка можно отсортировать в каноническом порядке, принятом в Mathematica, при помощи функции Sort[list]. Автоматически Mathematica производит сортировку списков следующим образом: целые, рациональные и вещественные числа сортируются по возрастанию значения, комплексные — по возрастанию значения действительной части, а при равных её значениях — по абсолютной величине мнимой части; символы и строки сортируются по алфавиту, степени и произведения сортируются так же, как и члены в полиноме, по возрастанию степени; в списках, содержащих смешанные данные (числа, символы строки), сначала сортируются численные данные, а за ними — "буквенные", т.е., символы и строки. Примеры In[1] и In[2] канонической сортировки см. на рис. 3.16.
Функция Sort[list,cond] позволяет отсортировать список в порядке, заданном пользователем, при чём cond — условие, по которому будет происходить сортировка. Например, если эту функцию мы применим к списку чисел list с условием cond равным Greater, то список будет сортирован по убыванию. Условие Greater можно записать в следующем виде: #1>#2. Подобная конструкция, как мы уже знаем, является анонимной функцией. Пример сортировки по заданному пользователем критерию In[3] и In[4] см. на рис. 3.16. Изменить направление сортировки можно также при помощи функции Reverse[list] — пример In[5].
Если мы попробуем автоматически отсортировать вложенный список, то упорядочение будет вестись по первому элементу каждого внутреннего списка, а списки с большим числом элементов будут располагаться после списков с меньшим числом — см. пример In[6] на рис. 3.16.
(рис 3.16) Сортировка элементов списка
В Mathematica имеются функции, позволяющие циклически переставлять элементы списков справа налево RotateLeft[list,n] и слева направо RotateRight[list,n], где n определяет число позиций, на которое следует сдвинуть элементы списка list в ту или иную сторону. Если параметр n опущен, то перестановка осуществляется на одну позицию. Примеры использования функций перемещения см. на рис. 3.17.
(рис 3.17) Циклическая перестановка элементов списка
Mathematica позволяет из линейных списков создавать вложенные списки. При помощи функции Partition[list,n] линейный список list преобразуется во вложенный список, причём внутренние списки не перекрываются и содержат по n элементов (см. пример In[1] на рис. 3.18). Для создания перекрывающихся списков используется функция в виде Partition[list,n,w], по выполнении которой генерируется вложенный список, содержащий n внутренних списков, причём w последних элементов предыдущего списка становятся w первыми элементами последующего списка (пример In[2]).
(рис 3.18) Создание вложенных списков на основе линейных
Возможна в программе и обратная операция — объединение элементов вложенного списка в один линейный список. Так функция Flatten[list], где list — вложенный список, убирает заголовок List у всех внутренних списков и превращает list в одноуровневый список. Заданная в более полном виде функция Flatten[list,n] убирает заголовок List только до уровня n включительно, т.е., список, полученный в результате выполнения этой функции, может быть и не одноуровневым. Соответствующие примеры см. на рис. 3.19.
(рис 3.19) Создание более низкоуровневых списков из вложенных списков
Обратимся теперь к функциям, которые рассматривают список скорее как множество, а не как упорядоченную структуру.
Простейшей для понимания из них является функция Join[list1,list2,...], осуществляющая сцепление (конкатенацию) списков независимо от содержащихся в них элементов (пример In[1] на рис. 3.20). Вообще говоря, в списке могут содержаться совпадающие элементы. Применение к нему функции Union[list] приводит к удалению повторений элементов и к сортировке оставшихся. Если аргумент этой функции будет содержать несколько списков, то результатом будет список, состоящий из элементов этих списков, причём повторяющиеся элементы также будут удалены.
Функция Intersection[list1,list2,...] возвращает список элементов списка list, содержащихся в списках list1, list2..., а Complement[list1,list2,...] — НЕ содержащихся в списках. Повторные элементы в результирующих списках также будут удалены. Примеры работы с повторяющимися элементами списков также см. на рис. 3.20.
Подробней о преобразовании списков см. книги Е. М. Воробьёва [1, с. 103–110] и П. Веллина и др. [14, с. 63–66, 69].
(рис 3.20) Операции с несколькими списками
Если мы попробуем вычислить значения некоторых встроенных функций Mathematica от списков, то на выходе получим список той же размерности, что и начальный, элементы которого являются результатом применения функции к каждому элементу списка в отдельности. См. на рис. 3.21 примеры применения к списку функции извлечения квадратного корня Sqrt[list] (In[1]), а также возведения в степень x^list (In[2]) и list^x (In[3]). Эти примеры демонстрируют свойство встроенных функций, которое можно назвать дистрибутивностью относительно списков (Е. М. Воробьёв [1, с. 118]).
Применение дистрибутивных функций к спискам одинаковой длины имеет свою специфику, которую доступно описывает Е. М. Воробьёв [1, с. 120]: "...при применении дистрибутивной функции от нескольких аргументов к спискам одинаковой длины происходит следующее: сначала производится транспозиция списков, т.е. объединяются в списки элементы с одинаковыми номерами из разных списков, потом функция применяется к вновь образованным спискам так, что элементы этих списков становятся аргументами функции". Иллюстрация сказанного представлена на примере In[4] на рис. 3.21. Сначала из трёх списков, содержащих по два элемента, сформировались два списка по три элемента. Затем заголовок List полученных списков был заменён заголовком Times.
(рис 3.21) Применение дистрибутивных функций к спискам
Если же к списку применить произвольную функцию f, то она, не обладая свойством дистрибутивности, даст неопределённый результат — пример In[1] на рис. 3.22. Однако заставить функцию f вести себя как дистрибутивную по отношению к списку list можно при помощи функции Map[f,list] — пример In[2] на рис. 3.22.
Если функция задана в виде Map[f,list,k], k задаёт спецификацию уровня, определяющую уровень списка list, к элементам которого будет применяться функция f — примеры In[3] и In[4] на рис. 3.22. Похожей по действию является функция MapAt[f,list,k]: она применяет заголовок f к элементам списка list в соответствии с их спецификацией — см. пример In[5].
Функция Attributes[function] позволяет узнать, является ли некоторая функция дистрибутивной относительно списков Если среди атрибутов функции function присутствует listable, то она дистрибутивна.
С функцией Map мы встретимся ещё раз, когда будем говорить о функциональном программировании в Mathematica.
Подробней об использовании списков в качестве аргументов функции см. книгу Е. М. Воробьёва [1, с. 117–123].
(рис 3.22) Добавление функции свойства дистрибутивности
Наиболее точно и ёмко векторы и матрицы в Mathematica определяет Е. М. Воробьёв [1, с. 110]: "Векторы в Mathematica трактуются как линейные, т.е. одноуровневые, списки: v={vl,v2,v3,...}; матрицы как двухуровневые: т={{mll,ml2,ml3,...},{m21,m22,m23,...}}, хотя компоненты векторов и матриц могут быть произвольными выражениями". Поскольку эти объекты играют немаловажную роль в математике и физике, разработчики Mathematica определили ряд функций, предназначенных для работы именно с ними.
Во-первых, это функции проверки, является ли список list вектором VectorQ[list] или матрицей MatrixQ[list]. При положительном результате функции возвращают True, иначе — False (см. пример на рис. 3.23).
(рис 3.23) Проверка списка на то, является ли он вектором или матрицей
Если некоторое выражение m действительно является матрицей, то к нему применимы описанные ниже функции.
Определитель (детерминант) матрицы m вычисляется функцией Det[m].
Функция Tr[m] возвращает след матрицы m.
Для невырожденных квадратных матриц можно вычислить обратную матрицу при помощи функции Inverse[m].
Функция Transpose[m] проводит транспонирование матрицы m.
Функция Minors[m,k] генерирует список миноров k-го порядка матрицы m.
Для нахождения скалярного произведения векторов, произведения вектора и матрицы, произведения матриц используется функция Dot[expr1,expr2]. В упрощённом виде, в так называемой инфиксной форме (shorthand notation), эту функцию можно задать как exprl.expr2.
Векторное произведение векторов v1 и v2 находится при помощи функции Cross[v1,v2].
Для нахождения нормы вектора v используется функция Norm[v].
Собственные числа и собственные векторы матриц находятся соответственно функциями Eigenvalues[expr] и Eigenvectors[expr], а одновременно и то, и другое — функцией Eigensystem[expr]. Функция CharacteristicPolynomial[expr] дает характеристический полином матрицы.
Некоторые примеры использования функций для работы с матрицами представлены на рис. 3.24.
Подробней о работе с векторами и матрицами см. книгу Е. М. Воробьёва [1, с. 110–112].
(рис 3.24) Работа с матрицами и векторами
Строки по своей структуре очень напоминают списки: в качестве элементов в строках используются символы и цифры. Поэтому многие функции, предназначенные для работы со строками, очень похожи по функционалу и способу задания параметров на функции для списков.
StringLength[str] возвращает длину (число символов) строки.
StringReverse[str] осуществляет запись символов строки в обратном порядке.
Функции Take[str,cond] и Drop[str,cond] позволяют обратиться к символам, имеющим заданные условиями cond номера, причём условия cond определяются так же, как и в соответствующих функциях для списков.
StringPosition[str,expr] показывает номер позиции выражений expr в строке str.
StringInsert[str,expr,n] добавляет выражение expr в строку str на позицию с номером n.
StringReplace[str,expr->expr2] заменяет в строке str выражение expr1 выражением expr2.
Примеры использования описанных выше функций см. на рис. 3.25.
(рис 3.25) Работа со строками
Функция Characters[str] позволяет конвертировать строку str в список. Однако элементами полученного списка будут не символы, содержащиеся в исходной строке, а строки, содержащие каждый символ в отдельности, т.е., функция Characters преобразует некоторую строку "abcdefg" в список {"a","b","c","d","e","f","g"} — см. примеры In[1] и In[2] на рис. 3.26.
Преобразовать список в строку позволяет функция StringJoin[list] — пример In[3] на рис. 3.26.
Подробней о работе со строками см. книгу П. Веллина и др. [14, с. 70–72].
(рис 3.26) Преобразование строк в списки и списков в строки
Вложенный список — список, элементами которого являются другие списки.
Внутренний список — список, являющийся элементом вложенного списка.
Глубина вложенного списка — число уровней вложенного списка.
Длина списка — число элементов списка.
Итератор — объект, указывающий на расположенные определённым образом элементы в наборе данных.
Список — форма структурирования данных, по строению представляющая собой множество элементов, заключённых в фигурные скобки и разделённых запятыми.
В данной лекции мы подробно познакомились с третьим классом данных Mathematica — списками. Мы научились задавать списки, как вручную, так и пользуясь широким спектром предназначенных для этого встроенных функций Mathematica. Мы познакомились с такими сложными объектами, как вложенные списки, также принципами их задания и работы с ними. Мы научились выявлять структуру списков, извлекать информацию о количестве и характере их элементов, о количестве уровней вложенных списков. Мы познакомились с встроенными функциями Mathematica, позволяющими избирательно обращаться к требуемым элементам списков, модифицировать списки. Мы узнали, какой эффект оказывает на результат вычислений применение к спискам математических функций. Мы более подробно познакомились с возможностями работы в системе Mathematica с такими объектами математики, как векторы и матрицы. Мы также научились более умело работать с объектами очень близкого по структуре к спискам класса данных Mathematica — строками.
Table?Table следующие списки:
{{1},{1,3},{1,3,5},{1,3,5,7},{1,3,5,7,9},{1,3,5,7,9,11}}
{{1,3,5,7,9,11},{3,5,7,9,11},{5,7,9,11},{7,9,11},{9,11},{11}}
{{11,9,7,5,3,1},{9,7,5,3,1},{7,5,3,1},{5,3,1},{3,1},{1}}
{{11,9,7,5,3,1},{11,9,7,5,3},{11,9,7,5},{11,9,7},{11,9},{11}}
+5, 0 и -5;+5 и -5 (один из способов — сгенерировать список бинарных значений 0 и 1, которые заменить соответствующим образом заданной парой значений)Array создайте список {{f[1,1],f[1,2],f[1,3]},{f[2,1],f[2,2],f[2,3]},{f[3,1],f[3,2],f[3,3]},{f[4,1],f[4,2],f[4,3]}}. Точно такой же список создайте при помощи функции Table.{1,-3,a,0,{a},b,0,0,{},1,{a,-3},-3,b,1} исключите
{{a,1},{b,2},{c,3},{d,4},{e,5}} в два списка {1,2,3,4,5} и {e,d,c,b,a}.{и,в,а,н,и,в,а,н,о,в,и,ч,и,в,а,н,о,в}).
Выполните следующие задания (в скобках указаны функции Mathematica, которыми следует пользоваться при выполнении задания).
FreeQ, MemberQ, Count, Position);Select, Take);ReplacePart, Delete, Insert);Delete, Drop);Append, Prepend);RotateLeft, RotateRight).{x-5,2*y+h,z} и {7*x-5,y+2*y^2,0.1z-Sqrt[z]} являются векторами, затем, не пользуясь функциями Dot, Cross, найдите их скалярное и векторное произведение. При помощи функций Dot, Cross проверьте результат.{{g,6,u},{4,j,9},{f,2,4}} является матрицей, найдите её определитель и постройте соответствующую ей транспонированную матрицу.Цель лекции: познакомиться с одним из основных классов данных Mathematica — списками, познакомиться с принципами работы с ними
Значительная доля вычислений так или иначе связана не с отдельными выражениями, а с целыми массивами тем или иным образом сгруппированных данных. Именно поэтому для работы с такими данными в Mathematica существует целый класс данных, называемый списками. Как мы помним из предыдущей лекции, список представляет собой удобную форму структурирования данных, по строению представляет собой множество элементов, заключённых в фигурные скобки { } и разделённых запятыми: {expr1,expr2,...}. Для каждой открывающей фигурной скобки { в списке должна присутствовать закрывающая фигурная скобка }. Элементами списка могут быть любые выражения: числа, символы, строки, функции, графические изображения, а также другие списки. Для работы со списками в Mathematica имеется широчайший набор инструментов: можно различными способами создавать списки, преобразовывать их, а также извлекать информацию из уже имеющихся списков. Для знакомства с указанными возможностями
воспользуемся логикой изложения материала в работе П. Веллина и др. [14].
В Mathematica список есть выражение, имеющее заголовок List, поэтому наиболее естественный для Mathematica способ задания списка — в виде List[element1,element2,...], где element1,element2,... — элементы списка (пример In[1] на рис. 3.1). С более простым и наглядным для пользователя способом задания списка мы уже познакомились в предыдущей лекции: он заключается в том, чтобы ввести через запятую элементы списка и обособить их фигурными скобками (пример In[2]).
Если список включает в себя только числа одного из трёх типов: целые, рациональные или вещественные — и элементы списка подчиняются какой-либо периодической закономерности, то задать список можно, воспользовавшись функцией Range[imin,imax,di]. В результате генерируется список от наименьшего значения imin с приращением (разностью между соседними элементами) di до значения меньшего или равного imax.
В примере In[3] на рис. 3.1 мы создаём список целых чисел, начиная от числа 2. Последующие элементы получаются добавлением к текущему элементу числа 3. Наибольшее значение элемента списка не будет превышать числа 19.
Если приращение di равняется единице, можно воспользоваться упрощённой версией функции — Range[imin,imax]. Так в примере In[4] на рис. 3.1 мы задаём список вещественных чисел, начиняя от числа 1.5. Поскольку приращение не задано, последующие элементы генерируются прибавлением к предыдущим элементам единицы. Наибольшее значение элемента списка не будет превышать числа 8.
Существует ещё более простая версия функции — Range[imax], которая задаёт ряд натуральных чисел от 1 до значения меньшего или равного imax: это может понадобиться, например, в случае, когда требуется задать нумерацию. Так в примере In[5] на рис. 3.1 мы генерируем ряд натуральных чисел от 1 до 10.
Подробней о функции Range см. книги Е. М. Воробьёва [1, с. 101, 161] и П. Веллина и др. [14, с. 55–56].
(рис 3.1) Простейшие способы задания списков
Mathematica позволяет задавать и более сложно устроенные списки числовых данных. Для этого используется функция Table. В наиболее полной своей форме функция выглядит следующим образом: Table[expr,{i,imin,imax,di}]. Первый аргумент функции, expr, представляет собой выражение, которое вычисляется в процессе построения списка, и вычисленное значение включается в список как один из его элементов. Второй аргумент функции, {i,imin,imax,di}, называется итератором (iterator). В случае Mathematica итератор можно рассматривать как объект, указывающий на расположенные определённым образом элементы в наборе данных. Итератор представляет собой перечень параметров, определяющих в конечном итоге число элементов списка. Параметры могут также входить в выражение expr в качестве констант или переменных. Параметр imin принимает численные значения и определяет первое значение переменного параметра i, приращение di — величина,
использующаяся для задания последующих элементов списка, число imax определяет наибольшее возможное значение i: если при возрастании значения i с интервалом di получается величина, превышающая imax, то построение списка заканчивается, а полученное значение при этом не используется.
В примере In[1] на рис. 3.2. при помощи функции Table мы задаём список элементов, удовлетворяющих выражению 2*k, причём k меняется от 1.1 до 15 с интервалом 2.
При помощи функции Table[i,{i,imin,imax,di}] можно продублировать уже известную нам функцию Range[imin,imax,di] (пример In[2] на рис. 3.2: ср. списки, полученные в Out[2]). И точно так же функцию Table можно записывать в упрощённом виде: Table[expr,{i,imin,imax}] — когда приращение равно единице, Table[expr,{i,imax}] — когда равны единице приращение di и первое значение переменного параметра i (соответствующие примеры In[4] и In[5]).
Если выражение expr не зависит от переменного параметра, то функцию можно записать как Table[expr,{imax}]: она генерирует ряд, содержащий число элементов, равное целой части выражения imax, причём каждый элемент содержит выражение expr. Однако здесь с подачи Е. М. Воробьёва [1, с. 101–102] необходимо сделать уточнение. Дело в том, что одно и то же исходное выражение expr в ряде случаев при вычислении может давать различные результаты. Для понимания этого неожиданного заявления рассмотрим функцию Random, часто используемую в математическом моделировании. Выражение Random[] в качестве результата вычисления возвращает однородно распределенную псевдослучайную вещественную величину, заключенную в интервале от 0 до 1. Поэтому выражения Table[Random[],{imax}] генерирует ряд случайных чисел со значением от 0 до 1, состоящий из imax числа элементов — см. пример
In[6] на рис. 3.2.
Скажем ещё несколько слов о функции Random. Выражение Random[type,{imin,imax}] задаёт случайное число, принадлежащее интервалу {imin,imax} и относящееся к типу type, где type принимает значения типов чисел, Integer, Real или Complex. В случае типа Real третий аргумент функции Random может задавать число цифр, используемых при задании вещественного числа.
Подробней о функции Random см. книгу Е. М. Воробьёва [1, с. 101–102].
В примере In[7] на рис. 3.2. мы генерируем целое число, принадлежащее промежутку от 5 до 101, а в In[8] — вещественное число из промежутка от 3.5 до 7.1, причём представляем его с точностью до пятнадцати значащих цифр.
(рис 3.2) Задание списков при помощи функции Table
Функция Table также позволяет генерировать вложенные списки, то есть, списки, элементами которых являются другие списки. Списки, являющиеся элементами вложенного списка, называются внутренними. Это делается путём добавления в функцию ещё одного итератора — пример In[1] на рис. 3.3. Когда функция содержит больше одного итератора, порядок итераторов оказывается существенным, поскольку значения внешнего итератора различны для каждого значения внутреннего итератора. В нашем примере In[1] для каждого значения j (внутренний итератор) параметр i (внешний итератор) изменяется от 1 до 3, при этом создаётся список из четырех элементов, каждый из которых содержит ещё по 3 элемента. Если мы поменяем в выражении In[1] порядок итераторов, то получим список из трех элементов, каждый из которых содержит по четыре элемента — пример In[2].
Подробней о функции Table см. книги Е. М. Воробьёва [1, с. 101–103] и П. Веллина и др. [14, с. 56–58].
(рис 3.3) Задание вложенных списков
Теперь разберёмся в терминологии. В предыдущих лекциях мы уже встречались понятием многоуровневости. Мы говорили о том, что любое выражение во внутреннем представлении являет собой многоуровневую структуру: на нулевом уровне содержится заголовок выражения, на первом — аргументы функции, определяемой заголовком, на втором — аргументы аргументов и так далее. Количество уровней внутренней формы соответствует максимальному номеру уровня в выражении плюс единица, то есть, в него входит и нулевой уровень.
Когда мы говорим о числе уровней списков, мы имеем в виду только те уровни, на которых содержатся элементы списков. Это значит, что ни о каком нулевом уровне списков речи не идёт, и, соответственно, количество уровней списка соответствует максимальному номеру уровня. Здесь также следует отметить, что заголовок списка List является нулевым элементом (но не уровнем!) списка, который он определяет.
Чтобы окончательно запутать читателей, отметим ещё следующее: список, как и всякое выражение, может быть представлен в полной форме. В этом случае следует заранее оговаривать, об уровнях списка или уровнях полной формы представления списка идёт речь.
Вложенные списки можно представлять на экране различными способами. С простейшим, "одноэтажным" способом мы уже подробным образом познакомились. Однако такое представление не является достаточно наглядным. Гораздо удобней выводить списки на экран в виде таблицы — функцией TableForm, и матрицы — функцией MatrixForm — см. соответствующие примеры In[1] и In[2] на рис. 3.4. Дополнительная опция TableHeads функции TableForm добавляет заголовки столбцам и строкам таблицы (пример In[3]).
Внешний итератор может зависеть от значения внутреннего итератора (П. Веллин и др. [14, с. 57]), в результате чего могут создаваться непрямоугольные списки — см. пример In[4] на рис. 3.4, в котором количество столбцов в таблице меняется с изменением номера строки. Но внутренний итератор зависеть от внешнего не может, поскольку, как мы видели выше, при генерации списка внутренний итератор должен иметь фиксированное значение, пока изменяется внешний.
(рис 3.4) Способы представления списков при помощи функций TableForm и MatrixForm
В Mathematica имеется функция DiagonalMatrix[list], позволяющая из заданного списка list порождать новый список, отвечающий диагональной матрице с элементами списка list на главной диагонали. Также имеется функция IdentityMatrix[n], порождающая единичную матрицу размерности n x n. Примеры задания таких матриц см. на рис. 3.5.
(рис 3.5) Задание диагональных матриц
Последним способом задания списков, с которым мы познакомимся в рамках данного курса, является использование функции с заголовком Array. Функция Array[a,n] порождает список длины п с элементами а[i], где i=1,2,...,n. Итератор, заданный в виде {n1,n2,...}, приводит к созданию вложенного списка — см. пример In[1]. Функция Array[a,it,origin] дает список, в котором индексы итераторов it изменяются, начиная со значения origin, по умолчанию равного единице (пример In[2]). Если же функция задана в полной форме, Array[а,it,origin,h], то получается выражение, в котором заголовок List всюду заменен заголовком h — пример In[3] на рис. 3.6.
Подробней о функции Array см. книгу Е. М. Воробьёва [1, с. 103].
(рис 3.6) Использование функции Array для задания списков
Списки относятся к данным сложной структуры. Поэтому при работе с ними возникает необходимость контроля над структурой, иначе применение списков может привести к грубым ошибкам, как явным, сопровождаемым выдачей сообщения об ошибке, так и неявным, на наличие которых Mathematica никаким образом не реагирует, но результаты расчётов оказываются неверными. Для выявления структуры списков в программе имеется ряд функций. Одна из них — Length. Она возвращает длину списка — число элементов списка. Если мы применим эту функцию к линейному (невложенному, не содержащему в качестве элементов других списков) списку, то мы получим число элементов, которое в нём содержится; для вложенных списков мы получим число внутренних списков в нём, при этом количество элементов в этих внутренних списках приниматься в расчёт не будет — см., соответственно, примеры In[1] и In[2] на рис. 3.7.
Если вложенный список полностью состоит из внутренних списков одинаковой длины, то всё-таки существует возможность получить информацию о длине внутренних списков: для этого следует воспользоваться функцией Dimensions. При помощи этой функции в примере In[3] на рис. 3.7 мы узнаём о том, что заданный список содержит два внутренних списка, каждый из которых сам состоит из трёх списков, содержащих по два элемента. Помогает нам функция Dimensions и в экзотическом случае, когда на каждом уровне вложенного списка содержится всего один элемент — пример In[4].
Если вложенный список list состоит из внутренних списков одинаковой длины только до определённого уровня n, то функция Dimensions поможет узнать структуру list только до этого уровня n включительно. Например, в трёхуровневом списке {{a,b},{c,{d,e}} на первом уровне находится два элемента, представляющих собой списки {a,b} и {c,{d,e}}. Каждый элемент-список также содержит по два элемента, которые являются элементами второго уровня: в первом случае — это символы a и b, а во втором — символ c и список {d,e}. На третьем уровне находятся только элементы списка {d,e}, очевидно, что символы a, b и c никаких элементов не содержат. Таким образом, для исходного списка количество элементов внутренних списков совпадает только до второго уровня включительно, и также до второго уровня этот список может быть описан функцией
Dimensions. Таким образом, вычисление выражения Dimensions[{{a,b},{c,{d,e}}] вернёт в выходной ячейке Out выражение {2,2}. Справедливость наших рассуждений подтверждается примером In[5] на рис. 3.7.
Если вложенный список состоит из списков одинаковой длины, то для того, чтобы определить глубину этого вложенного списка, то есть, число уровней, на которое необходимо спуститься, чтобы добраться до выражения, не являющегося списком, используется функция ArrayDepth — пример In[6] на рис. 3.7.
Подробней о получении информации о длине и глубине списков см. книгу П. Веллина и др. [14, с. 58–59].
(рис 3.7) Определение структуры линейных и вложенных списков
Если список expr является тензором, то функция TensorRank[expr] позволяет определить ранг этого тензора — рис. 3.8.
(рис 3.8) Определение ранга тензора
Крайне полезной в Mathematica является возможность проверять списки на содержание тех или иных выражений. Так функция FreeQ[list,form] возвращает True, если список list НЕ содержит выражения form; также в пакете имеется в некоторой мере дублирующая функция MemberQ[list,form], которая напротив возвращает True, если список list содержит выражение form (см. примеры In[1], In[2] и In[3] на рис. 3.9). А функция Position[list,form] возвращает позицию искомого элемента form в списке list. В нашем примере In[4] буква c занимает позицию с номером 3. Если список list не содержит выражения form, то возвращается пустой список {}.
Эта же функция поможет нам, если мы хотим узнать позицию того или иного выражения во вложенном списке. Отличие будет лишь в представлении результата. В примере In[5] на рис. 3.9 буква h занимает позицию под номером 2 в третьем элементе вложенного списка.
Узнать, сколько раз некоторый элемент elem встречается в списке list, можно с помощью функции Count[list,elem]. Если список list не содержит выражения elem, то Count возвращает 0. Так в примере In[6] на рис. 3.9 мы выяснили, что символ b содержится в заданном списке 3 раза.
(рис 3.9) Проверка списка на содержание в нём заданных выражений
Ещё одна функция Select[list,cond] позволяет выбирать элементы списка list, возвращающие True при применении к ним предиката cond. В примере In[1] на рис. 3.10 из списка выбираются только чётные числа.
Для того чтобы выбрать из списка list только одинаковые элементы elem, недостаточно просто указать elem вместо условия cond: в этом случае будет просто сгенерирован пустой список (см. пример In[2] на рис. 3.10). Для этого следует задать условие с использованием анонимной функции в виде #==elem. Так в примере In[3] мы выбираем из исходного списка только двойки. С анонимными функциями мы подробней познакомимся в лекции 9 настоящего курса, посвящённой функциональному программированию.
Если условию cond не соответствует ни один элемент списка list, то Select[list,cond] генерирует пустой список.
Подробней о функциях проверки содержания списка см. книгу П. Веллина и др. [14, с. 60–61].
(рис 3.10) Выбор элементов списка по условию
При помощи функции Part[list,n] можно извлечь из списка list элемент, зная его позицию n в списке. Эту функцию также можно задать в сокращённом виде, используя двойные скобки: list[[n]]. Чтобы обратиться сразу к нескольким элементам списка, следует задать функцию в виде Part[list,{n1,n2,...}] или list[[{n1,n2,...}]], где n1,n2,... — номера элементов, которые требуется извлечь.
В примере In[1] на рис. 3.11 мы задали одноуровневый список list, в In[2] при помощи полной формы функции Part мы извлекли второй элемент списка list, а в In[3], — используя сокращённую форму, третий и пятый элементы.
(рис 3.11) Извлечение элементов линейных списков
Для того чтобы извлечь элемент из вложенного списка, необходимо указать и номер подсписка, в котором находится необходимый элемент, и номер элемента в этом подсписке. На рис. 3.12 приведён пример извлечения элементов матрицы 3х3. В примере In[2] мы извлекаем элемент с номером 2 из третьего подсписка. В примере In[3] мы полностью извлекаем второй столбец матрицы, заменив номер подсписка на выражение All, а в примере In[4] — третью строку, которая также является третьим подсписком исходного списка, причём мы можем либо заменить номер элемента на All, либо вовсе опустить этот параметр.
(рис 3.12) Извлечение элементов вложенных списков
Для обращения к элементам списка в Mathematica имеется ещё одна функция — с заголовком Take. В своей простейшей форме Take[list,{b1,b2}] она возвращает фрагмент списка list, содержащий элементы с номерами от b1 до b2, причём если b1, b2 принимают положительные значения, то номер элемента отсчитывается от первого (пример In[1] на рис. 3.13), а если отрицательные — от последнего (пример In[2]). При этом b1 и b2 могут принимать положительные и отрицательные значения независимо друг от друга (пример In[3]).
Если функция задаётся в виде b — от элемента с номером абсолютного значения b с конца списка до последнего элемента в списке (примеры In[4] и In[5] на рис. 3.13).
В наиболее полной форме Take[list,{b1,b2,di}] функция из списка list выбирает каждый di-й элемент, начиная с элемента под номером b1 и заканчивая элементом с номером, не большим, чем b2 (пример In[6] на рис. 3.13).
Подробней об управлении содержанием списка см. книги Е. М. Воробьёва [1, с. 105–106] и П. Веллина и др. [14, с. 62–63].
(рис 3.13) Использование функции Take для извлечения фрагментов списков
Mathematica позволяет отбрасывать фрагменты списка при помощи функции Drop[list,bound], где bound задаёт фрагмент списка list, который необходимо отбросить. Правила задания функции Drop такие же, как и для Take. Примеры отбрасывания элементов в начале, конце и в произвольном месте списка представлены на рис. 3.14 как In[1], In[2] и In[3], соответственно.
Помимо отбрасывания целых фрагментов Mathematica позволяет селективно удалять элементы списка с определёнными номерами при помощи функции Delete[list,{{n1},{n2},...}], где n1,n2,...— номера элементов списка list, которые необходимо удалить — примеры In[4] и In[5] на рис. 3.14.
(рис 3.14) Удаление элементов списка
Mathematica позволяет добавлять в списки новые элементы. Для добавления элементов в начало и конец списка имеются соответствующие функции: Prepend[list,n] и Append[list,elem] (см. примеры In[1] и In[2] на рис. 3.15).
Функция Insert[list,elem,n] помещает выражение elem на позицию n в списке list, причём число n может принимать как положительные, так и отрицательные значения (пример In[3] на рис. 3.15).
Как мы уже отмечали, элементами списка могут быть любые выражения, в том числе и списки. Новый элемент elem можно вставить в любой внутренний список в списке list или внутрь любого элемента списка, если этот элемент не является атомарным выражением. В примере In[4] на рис. 3.15 указание позиции в виде {1,2} означает, что новый элемент нужно вставить в первый элемент списка на вторую позицию. Один и тот же элемент можно вставить на несколько позиций — см. пример In[5].
Mathematica позволяет осуществлять суперпозицию описанных выше функций удаления и добавления элементов в список — заменять один элемент другим. Делается это при помощи функции ReplaceRart[list,elem,n], которая заменяет элемент списка list под номером n элементом elem — см. пример In[6] на рис. 3.15.
(рис 3.15) Добавление элементов в список
Элементы списка можно отсортировать в каноническом порядке, принятом в Mathematica, при помощи функции Sort[list]. Автоматически Mathematica производит сортировку списков следующим образом: целые, рациональные и вещественные числа сортируются по возрастанию значения, комплексные — по возрастанию значения действительной части, а при равных её значениях — по абсолютной величине мнимой части; символы и строки сортируются по алфавиту, степени и произведения сортируются так же, как и члены в полиноме, по возрастанию степени; в списках, содержащих смешанные данные (числа, символы строки), сначала сортируются численные данные, а за ними — "буквенные", т.е., символы и строки. Примеры In[1] и In[2] канонической сортировки см. на рис. 3.16.
Функция Sort[list,cond] позволяет отсортировать список в порядке, заданном пользователем, при чём cond — условие, по которому будет происходить сортировка. Например, если эту функцию мы применим к списку чисел list с условием cond равным Greater, то список будет сортирован по убыванию. Условие Greater можно записать в следующем виде: #1>#2. Подобная конструкция, как мы уже знаем, является анонимной функцией. Пример сортировки по заданному пользователем критерию In[3] и In[4] см. на рис. 3.16. Изменить направление сортировки можно также при помощи функции Reverse[list] — пример In[5].
Если мы попробуем автоматически отсортировать вложенный список, то упорядочение будет вестись по первому элементу каждого внутреннего списка, а списки с большим числом элементов будут располагаться после списков с меньшим числом — см. пример In[6] на рис. 3.16.
(рис 3.16) Сортировка элементов списка
В Mathematica имеются функции, позволяющие циклически переставлять элементы списков справа налево RotateLeft[list,n] и слева направо RotateRight[list,n], где n определяет число позиций, на которое следует сдвинуть элементы списка list в ту или иную сторону. Если параметр n опущен, то перестановка осуществляется на одну позицию. Примеры использования функций перемещения см. на рис. 3.17.
(рис 3.17) Циклическая перестановка элементов списка
Mathematica позволяет из линейных списков создавать вложенные списки. При помощи функции Partition[list,n] линейный список list преобразуется во вложенный список, причём внутренние списки не перекрываются и содержат по n элементов (см. пример In[1] на рис. 3.18). Для создания перекрывающихся списков используется функция в виде Partition[list,n,w], по выполнении которой генерируется вложенный список, содержащий n внутренних списков, причём w последних элементов предыдущего списка становятся w первыми элементами последующего списка (пример In[2]).
(рис 3.18) Создание вложенных списков на основе линейных
Возможна в программе и обратная операция — объединение элементов вложенного списка в один линейный список. Так функция Flatten[list], где list — вложенный список, убирает заголовок List у всех внутренних списков и превращает list в одноуровневый список. Заданная в более полном виде функция Flatten[list,n] убирает заголовок List только до уровня n включительно, т.е., список, полученный в результате выполнения этой функции, может быть и не одноуровневым. Соответствующие примеры см. на рис. 3.19.
(рис 3.19) Создание более низкоуровневых списков из вложенных списков
Обратимся теперь к функциям, которые рассматривают список скорее как множество, а не как упорядоченную структуру.
Простейшей для понимания из них является функция Join[list1,list2,...], осуществляющая сцепление (конкатенацию) списков независимо от содержащихся в них элементов (пример In[1] на рис. 3.20). Вообще говоря, в списке могут содержаться совпадающие элементы. Применение к нему функции Union[list] приводит к удалению повторений элементов и к сортировке оставшихся. Если аргумент этой функции будет содержать несколько списков, то результатом будет список, состоящий из элементов этих списков, причём повторяющиеся элементы также будут удалены.
Функция Intersection[list1,list2,...] возвращает список элементов списка list, содержащихся в списках list1, list2..., а Complement[list1,list2,...] — НЕ содержащихся в списках. Повторные элементы в результирующих списках также будут удалены. Примеры работы с повторяющимися элементами списков также см. на рис. 3.20.
Подробней о преобразовании списков см. книги Е. М. Воробьёва [1, с. 103–110] и П. Веллина и др. [14, с. 63–66, 69].
(рис 3.20) Операции с несколькими списками
Если мы попробуем вычислить значения некоторых встроенных функций Mathematica от списков, то на выходе получим список той же размерности, что и начальный, элементы которого являются результатом применения функции к каждому элементу списка в отдельности. См. на рис. 3.21 примеры применения к списку функции извлечения квадратного корня Sqrt[list] (In[1]), а также возведения в степень x^list (In[2]) и list^x (In[3]). Эти примеры демонстрируют свойство встроенных функций, которое можно назвать дистрибутивностью относительно списков (Е. М. Воробьёв [1, с. 118]).
Применение дистрибутивных функций к спискам одинаковой длины имеет свою специфику, которую доступно описывает Е. М. Воробьёв [1, с. 120]: "...при применении дистрибутивной функции от нескольких аргументов к спискам одинаковой длины происходит следующее: сначала производится транспозиция списков, т.е. объединяются в списки элементы с одинаковыми номерами из разных списков, потом функция применяется к вновь образованным спискам так, что элементы этих списков становятся аргументами функции". Иллюстрация сказанного представлена на примере In[4] на рис. 3.21. Сначала из трёх списков, содержащих по два элемента, сформировались два списка по три элемента. Затем заголовок List полученных списков был заменён заголовком Times.
(рис 3.21) Применение дистрибутивных функций к спискам
Если же к списку применить произвольную функцию f, то она, не обладая свойством дистрибутивности, даст неопределённый результат — пример In[1] на рис. 3.22. Однако заставить функцию f вести себя как дистрибутивную по отношению к списку list можно при помощи функции Map[f,list] — пример In[2] на рис. 3.22.
Если функция задана в виде Map[f,list,k], k задаёт спецификацию уровня, определяющую уровень списка list, к элементам которого будет применяться функция f — примеры In[3] и In[4] на рис. 3.22. Похожей по действию является функция MapAt[f,list,k]: она применяет заголовок f к элементам списка list в соответствии с их спецификацией — см. пример In[5].
Функция Attributes[function] позволяет узнать, является ли некоторая функция дистрибутивной относительно списков Если среди атрибутов функции function присутствует listable, то она дистрибутивна.
С функцией Map мы встретимся ещё раз, когда будем говорить о функциональном программировании в Mathematica.
Подробней об использовании списков в качестве аргументов функции см. книгу Е. М. Воробьёва [1, с. 117–123].
(рис 3.22) Добавление функции свойства дистрибутивности
Наиболее точно и ёмко векторы и матрицы в Mathematica определяет Е. М. Воробьёв [1, с. 110]: "Векторы в Mathematica трактуются как линейные, т.е. одноуровневые, списки: v={vl,v2,v3,...}; матрицы как двухуровневые: т={{mll,ml2,ml3,...},{m21,m22,m23,...}}, хотя компоненты векторов и матриц могут быть произвольными выражениями". Поскольку эти объекты играют немаловажную роль в математике и физике, разработчики Mathematica определили ряд функций, предназначенных для работы именно с ними.
Во-первых, это функции проверки, является ли список list вектором VectorQ[list] или матрицей MatrixQ[list]. При положительном результате функции возвращают True, иначе — False (см. пример на рис. 3.23).
(рис 3.23) Проверка списка на то, является ли он вектором или матрицей
Если некоторое выражение m действительно является матрицей, то к нему применимы описанные ниже функции.
Определитель (детерминант) матрицы m вычисляется функцией Det[m].
Функция Tr[m] возвращает след матрицы m.
Для невырожденных квадратных матриц можно вычислить обратную матрицу при помощи функции Inverse[m].
Функция Transpose[m] проводит транспонирование матрицы m.
Функция Minors[m,k] генерирует список миноров k-го порядка матрицы m.
Для нахождения скалярного произведения векторов, произведения вектора и матрицы, произведения матриц используется функция Dot[expr1,expr2]. В упрощённом виде, в так называемой инфиксной форме (shorthand notation), эту функцию можно задать как exprl.expr2.
Векторное произведение векторов v1 и v2 находится при помощи функции Cross[v1,v2].
Для нахождения нормы вектора v используется функция Norm[v].
Собственные числа и собственные векторы матриц находятся соответственно функциями Eigenvalues[expr] и Eigenvectors[expr], а одновременно и то, и другое — функцией Eigensystem[expr]. Функция CharacteristicPolynomial[expr] дает характеристический полином матрицы.
Некоторые примеры использования функций для работы с матрицами представлены на рис. 3.24.
Подробней о работе с векторами и матрицами см. книгу Е. М. Воробьёва [1, с. 110–112].
(рис 3.24) Работа с матрицами и векторами
Строки по своей структуре очень напоминают списки: в качестве элементов в строках используются символы и цифры. Поэтому многие функции, предназначенные для работы со строками, очень похожи по функционалу и способу задания параметров на функции для списков.
StringLength[str] возвращает длину (число символов) строки.
StringReverse[str] осуществляет запись символов строки в обратном порядке.
Функции Take[str,cond] и Drop[str,cond] позволяют обратиться к символам, имеющим заданные условиями cond номера, причём условия cond определяются так же, как и в соответствующих функциях для списков.
StringPosition[str,expr] показывает номер позиции выражений expr в строке str.
StringInsert[str,expr,n] добавляет выражение expr в строку str на позицию с номером n.
StringReplace[str,expr->expr2] заменяет в строке str выражение expr1 выражением expr2.
Примеры использования описанных выше функций см. на рис. 3.25.
(рис 3.25) Работа со строками
Функция Characters[str] позволяет конвертировать строку str в список. Однако элементами полученного списка будут не символы, содержащиеся в исходной строке, а строки, содержащие каждый символ в отдельности, т.е., функция Characters преобразует некоторую строку "abcdefg" в список {"a","b","c","d","e","f","g"} — см. примеры In[1] и In[2] на рис. 3.26.
Преобразовать список в строку позволяет функция StringJoin[list] — пример In[3] на рис. 3.26.
Подробней о работе со строками см. книгу П. Веллина и др. [14, с. 70–72].
(рис 3.26) Преобразование строк в списки и списков в строки
Вложенный список — список, элементами которого являются другие списки.
Внутренний список — список, являющийся элементом вложенного списка.
Глубина вложенного списка — число уровней вложенного списка.
Длина списка — число элементов списка.
Итератор — объект, указывающий на расположенные определённым образом элементы в наборе данных.
Список — форма структурирования данных, по строению представляющая собой множество элементов, заключённых в фигурные скобки и разделённых запятыми.
В данной лекции мы подробно познакомились с третьим классом данных Mathematica — списками. Мы научились задавать списки, как вручную, так и пользуясь широким спектром предназначенных для этого встроенных функций Mathematica. Мы познакомились с такими сложными объектами, как вложенные списки, также принципами их задания и работы с ними. Мы научились выявлять структуру списков, извлекать информацию о количестве и характере их элементов, о количестве уровней вложенных списков. Мы познакомились с встроенными функциями Mathematica, позволяющими избирательно обращаться к требуемым элементам списков, модифицировать списки. Мы узнали, какой эффект оказывает на результат вычислений применение к спискам математических функций. Мы более подробно познакомились с возможностями работы в системе Mathematica с такими объектами математики, как векторы и матрицы. Мы также научились более умело работать с объектами очень близкого по структуре к спискам класса данных Mathematica — строками.
Table?Table следующие списки:
{{1},{1,3},{1,3,5},{1,3,5,7},{1,3,5,7,9},{1,3,5,7,9,11}}
{{1,3,5,7,9,11},{3,5,7,9,11},{5,7,9,11},{7,9,11},{9,11},{11}}
{{11,9,7,5,3,1},{9,7,5,3,1},{7,5,3,1},{5,3,1},{3,1},{1}}
{{11,9,7,5,3,1},{11,9,7,5,3},{11,9,7,5},{11,9,7},{11,9},{11}}
+5, 0 и -5;+5 и -5 (один из способов — сгенерировать список бинарных значений 0 и 1, которые заменить соответствующим образом заданной парой значений)Array создайте список {{f[1,1],f[1,2],f[1,3]},{f[2,1],f[2,2],f[2,3]},{f[3,1],f[3,2],f[3,3]},{f[4,1],f[4,2],f[4,3]}}. Точно такой же список создайте при помощи функции Table.{1,-3,a,0,{a},b,0,0,{},1,{a,-3},-3,b,1} исключите
{{a,1},{b,2},{c,3},{d,4},{e,5}} в два списка {1,2,3,4,5} и {e,d,c,b,a}.{и,в,а,н,и,в,а,н,о,в,и,ч,и,в,а,н,о,в}).
Выполните следующие задания (в скобках указаны функции Mathematica, которыми следует пользоваться при выполнении задания).
FreeQ, MemberQ, Count, Position);Select, Take);ReplacePart, Delete, Insert);Delete, Drop);Append, Prepend);RotateLeft, RotateRight).{x-5,2*y+h,z} и {7*x-5,y+2*y^2,0.1z-Sqrt[z]} являются векторами, затем, не пользуясь функциями Dot, Cross, найдите их скалярное и векторное произведение. При помощи функций Dot, Cross проверьте результат.{{g,6,u},{4,j,9},{f,2,4}} является матрицей, найдите её определитель и постройте соответствующую ей транспонированную матрицу.Для получения официальных документов о завершении программы дополнительного профессионального образования (удостоверения о повышении квалификации, дипломов о профессиональной переподготовке и MBA) необходимо предоставить:
Внимание! Вы можете не заказывать доставку бумажной версии официального документы, а скачать его в электронном виде и распечатать самостоятельно. Информация о выданном документе в течение 1 месяца загружается в Федеральную информационную систему «Федеральный реестр сведений о документах об образовании и (или) о квалификации, документах об обучении» - ФИС ФРДО.
Доступ на новый сайт осуществляется с использованием адреса электронной почты, который был указан вами при регистрации на "старом". Мы постарались перенести все ваши данные с прежнего ресурса, однако не исключена вероятность потери части информации.
При возникновении проблемы со входом, воспользуйтесь функцией сброса пароля
Если вы обнаружите несоответствия, пожалуйста, сообщите нам.