Многомерные массивы и массивы массивов
Если возникает необходимость хранить данные в виде таблиц, матриц, кубов данных или более сложных структур, то язык Перфолента предлагает использовать многомерные массивы или массивы массивов. Специальный синтаксис позволяет сделать это удобным и хорошо читаемым способом.

В предыдущей статье мы подробно разобрали работу с одномерными массивами. Однако в реальных задачах часто возникает необходимость хранить данные в виде таблиц, матриц или более сложных структур. Для этих целей в языке Перфолента.Net предусмотрены многомерные массивы и массивы массивов. В этой статье мы рассмотрим, как объявлять, инициализировать, изменять и эффективно использовать такие структуры данных.
В языке Перфолента.Net поддерживаются:
- многомерный
массив — это один
массив, содержащий данные нескольких измерений. Объявляются как
ТипЭлементов[, … ,], например,Целое[,]илиЦелое[,,]. - массив массивов — это несколько вложенных друг в друга одномерных
или многомерных массивов, где каждый массив содержит данные одного или
нескольких измерений. Объявляются как
ТипЭлементов[]…[], например,Целое[][]илиЦелое[][][]; - а
также их произвольные комбинации, например,
Целое[][,][].
Умнику на заметку: Существуют
понятия нумерация и индексация. Нумерация начинается с единицы, а
индексация начинается с нуля. Индекс элемента на единицу меньше, чем его номер.
Для обращения к элементам массивов используются индексы!
Что такое многомерный массив?
Многомерный массив — это массив, состоящий из нескольких измерений, для доступа к элементам которого необходимо указать несколько индексов, по одному для каждого измерения. Наиболее часто используются двумерные массивы, которые можно представить в виде прямоугольной таблицы со строками и столбцами или матрицы. Трёхмерный массив можно визуализировать как куб или массив таблиц. Четырёхмерный как массив кубов, и так далее.
Объявление многомерных массивов
Для создания типа многомерного массива в квадратных скобках указывается соответствующее количество запятых, отделяющих измерения массива. Количество запятых на единицу меньше размерности (количества измерений) массива.
Для объявления многомерного массива (как и одномерного) в языке программирования Перфолента существует оператор Массив (странно, если бы он назывался иначе). Выглядит это так:
// Объявление пустого двумерного
массива целых чисел
Массив А[2,3] тип Целое
В этом примере мы создали таблицу данных 3 × 4 (а не 2 × 3) элементов типа Целое, т.к. существует элемент с индексом 0, к которому мы можем обратиться так А[0]. Это значит, что при создании массива мы указываем для каждого измерения верхний индекс, а не количество элементов, как в некоторых других языках программирования. Если вы случайно укажете количество элементов, то ничего страшного не произойдет, у вас просто будет одно лишнее место в измерении массива.
Умнику на заметку: Как и при объявлении переменной, к моменту объявления имя массива не должно быть занято.
В одном операторе мы можем создать несколько массивов с элементами одного типа:
//
Объявление двумерного и трёхмерного массивов с элементами одного типа
Массив МатрицаСлов[999,999], КубСлов[99,99,99] тип Строка
Мы так же можем задать элементам массива начальное значение, указав его после знака равно:
Массив
А[4,9] тип Целое = 1
В результате в массиве будет 5 × 10 = 50 единиц.
Внимание! Выражение задающее начальное значение будет вычислено столько раз, сколько элементов в массиве! Это позволяет последовательно заполнять элементы разными значениями, например:
ин = 1
// Элементы этих массивов будут заполнены последовательностью
// чисел от 1 до 21 (9+4*3)
Массив аа[8],
бб[3,2] = ин++
ин = 1
// Элементами массива тт будут три объекта типа
СуперСтрока,
// содержащих фразы Индекс=1, Индекс=2 и Индекс=3
Массив тт[2]
= Новый СуперСтрока("Индекс="+ин++)
// Двумерный массив, в каждой ячейке которого лежат
индексы ячейки
ин1=0
ин2=0
Массив м[2,3] =
""+?(ин2%4=3,
ин1++, ин1)%3+","+ин2++%4
Умнику на заметку: т.к. существуют значения структурного и ссылочного типов, то надо помнить об этом при инициализации массивов. Понятно, что все элементы массива структурного типа будут содержать собственные копии значения. А вот элементы массива ссылочного типа могут содержать ссылки на один и тот же объект или на разные, в зависимости от инициализирующего выражения. Надо просто помнить, что инициализирующее выражение вычисляется столько раз, сколько элементов в создаваемом массиве. Подробнее о структурных и ссылочных типах можно прочитать здесь: Переменные. Объявление переменных, инициализация и их использование..
Ещё примеры:
// Создание пустого двумерного
массива без элементов
Массив мцп4[,]
тип Целое
// Или так
Массив мцп5[-1,-1]
тип Целое
// Двумерный массив 3×3 (индексы от 0 до 2 по
каждому измерению)
Массив МИ[2,2]
тип Строка
// Трёхмерный массив по два элемента на
измерение
Массив МАС3М[1,1,1]
тип Вещ
Вместо создания массивов оператором Массив, можно создавать переменные имеющие тип массива и присваивать им массив, созданный ранее оператором Массив, или создавая массив на лету оператором Новый.
// Объявление переменной
двумерного массива целых чисел
// не содержащей массива (даже пустого)
Перем мп0
тип Целое[,]
= Неопределено
// Объявление переменной двумерного массива
целых чисел
// и присвоение ей ссылки на существующий массив
Перем мп1
тип Целое[,]
= мцп4
// Создание пустого двумерного массива без
элементов
Перем мп2
тип Целое[,]
= Новый Целое[,]
// Или с явным указанием индексов без элементов
Перем мп3
тип Целое[,]
= Новый Целое[-1,-1]
// Создание двумерного массива из 11×21 элементов
Перем мп4
тип Целое[,]
= Новый Целое[10,20]
Как и для обычных переменных, переменные имеющие тип массива можно создавать неявно, когда тип переменной определяется типом выражения.
// Объявление переменной
двумерного массива целых чисел
// и присвоение ей ссылки на существующий массив
мп10 = мцп4
// Создание пустого двумерного массива без
элементов
мп20 = Новый
Целое[,]
// Или с явным указанием индексов без элементов
мп30 = Новый
Целое[-1,-1]
// Создание двумерного массива из 11×21 элементов
мп40 = Новый
Целое[10,20]
Умнику на заметку: Неявное объявление переменных и массивов возможно только в том случае, если в программе отсутствует директива препроцессора #ТребоватьОбъявлениеПеременных.
Доступ к элементам многомерного массива
Для доступа к элементам многомерного массива, как и при его создании, используются индексы, разделённые запятыми:
// Создаём двумерный массив строк
Массив МИ[2,2]
тип Строка
// Устанавливаем значение элемента
МИ[1,1] = "58с"+33333
ВыводСтроки "МИ[1,1] = "+МИ[1,1]
// Заполняем массив значениями
Для Инд1 =
0 По 2
Для Инд2 = 0
По 2
МИ[Инд1,
Инд2] = ""+Инд1+","+Инд2
ВыводСтроки "МИ["+Инд1+","+Инд2+"]
= "+МИ[Инд1,Инд2]
КонецЦикла;
КонецЦикла;
Инициализация многомерных массивов
Инициализация при объявлении
Многомерные массивы можно инициализировать непосредственно при создании с помощью вложенных инициализаторов:
// Двумерный массив целых чисел
масИниЦел2М = {{0, 1},{0, 2}}
ВыводСтроки "масИниЦел2М[1,1]="+масИниЦел2М[1,1]
Инициализация с помощью оператора «Новый»
Как и в предыдущем случае, при создании многомерного массива оператором Новый можно инициализировать массив с помощью вложенных инициализаторов:
// Двумерный массив вещественных
чисел 3×3
Перем МАС2М
= Новый Вещ[2,2]{
{0.0, 0.1, 0.2},
{1.0, 1.1, 1.2},
{2.0, 2.1, 2.2}
};
// Трёхмерный массив
Перем МАС3М
= Новый Вещ[1,1,1]{
{{0.00, 0.01}, {0.10, 0.11}},
{{1.00, 1.01}, {1.10, 1.11}}
};
Инициализация существующего массива
Уже существующий многомерный массив так же можно инициализировать с помощью вложенных инициализаторов:
// Инициализируем существующий
массив набором значений
МАС3М{
{{0.00, 0.01}, {0.10, 0.11}},
{{1.00, 1.01}, {1.10, 1.11}}
};
Операции с многомерными массивами
Изменение размера
Для изменения размера массива используется оператор МассивИзменить:
// Изменение размера двумерного
массива
МассивИзменить мЧ25[5,10]
// Разрешается писать с пробелом
Массив Изменить мЧ25[5,10]
Важно: при изменении размера многомерного массива можно изменять только последнюю размерность! Попытка изменить другие размерности приведёт к ошибке:
Попытка
// Тут будет ошибка, т.к. изменять можно
только последнюю размерность массива
МассивИзменить мЧ25[10,20]
Исключение Ош
ВыводСтроки "Ошибка при МассивИзменить
мЧ25[10,20] - "+Ош.ОписаниеОшибки()
КонецПопытки
Производительность при изменении размера
При работе с массивами важно учитывать производительность.
Приведём тест, сравнивающий ручное изменение размера массива с использованием
оператора МассивИзменить:
// Ручное изменение размера
т0 = ТекущаяУниверсальнаяДатаВМиллисекундах()
мЫ1 = Новый Целое[3]{1,2,3,4}
Для Инд1 = 1 По 20000
мЫ2 = Новый Целое[Инд1]
Для Инд2 = 0
По Инд1-1
мЫ2[Инд2]
= мЫ1[Инд2]
КонецЦикла
мЫ1 = мЫ2
КонецЦикла
т1 = ТекущаяУниверсальнаяДатаВМиллисекундах()
ВыводСтроки("~"+ Цел(т1-т0) )
// С использованием оператора МассивИзменить
т2 = ТекущаяУниверсальнаяДатаВМиллисекундах()
мЫ1 = Новый Целое[3]{1,2,3,4}
Для Инд1 = 0 По 20000
// Работает от 4 до 10 раз быстрее, чем то же
самое вручную
МассивИзменить мЫ1[Инд1]
КонецЦикла
т3 = ТекущаяУниверсальнаяДатаВМиллисекундах()
ВыводСтроки("~"+ Цел(т3-т2) )
ВыводСтроки "Соотношение: "+(Вещ(т1-т0)/(т3-т2))+" раз."
Очистка массива
Оператор МассивОчистить устанавливает всем элементам значения по умолчанию
для заданного типа:
// Очистка нескольких массивов
сразу
МассивОчистить мСтр,
масИниЦел2М
// Разрешается писать с пробелом
Массив Очистить мСтр,
масИниЦел2М
ВыводСтроки "мСтр[0]="+ЕслиНеопределено(мСтр[0],"Элементы
очистились...")
Удаление массива
Оператор МассивУдалить присваивает переменной массива значение Неопределено.
Если на массив не осталось других ссылок, то он будет удален из памяти при
сборке мусора:
// Удаление нескольких массивов
сразу
МассивУдалить мСтр,
масИниЦел2М
// Разрешается писать с пробелом
Массив Удалить мСтр,
масИниЦел2М
ВыводСтроки "мСтр="+?(мСтр Это Неопределено,"Массив
НЕ определен!!!","Массив определен!!!")
Сравнение многомерных массивов
Массивы в языке Перфолента.Net сравниваются как объекты ИПеречисляемый (IEnumerable), что на практике означает последовательное сравнение друг с другом всех элементов двух массивов:
ма1 = {2,4}
ма2 = {2,4}
ВыводСтроки "ма1=ма2 "+(ма1=ма2)
ВыводСтроки "ма1<>ма2 "+(ма1<>ма2)
Помимо многомерных массивов, в языке Перфолента.Net поддерживаются массивы массивов. Их принципиальное отличие: каждый вложенный массив может иметь свой собственный размер. Такая структура удобна, когда данные «рваные» — например, строки таблицы имеют разное количество столбцов.
Простой массив массивов
Объявляется через последовательность пустых квадратных
скобок в описании типа: Целое[][] — массив, каждый элемент которого
является массивом целых чисел. Создаётся такой массив так же, как и обычный, с
указанием размеров на каждом уровне:
// Создаём массив из 2 элементов,
каждый из которых — массив из 5 целых
Перем МММ2
тип Целое[][]
= Новый Целое[1][4]
// Проверим типы на каждом уровне
Для Инд1
= 0 По 1
ВыводСтроки ""+ТипЗнч(МММ2[Инд1])+" "+Инд1
Для Инд4 = 0
По 4
ВыводСтроки ""+ТипЗнч(МММ2[Инд1][Инд4])+"
"+Инд1+" "+Инд4
КонецЦикла
КонецЦикла
// Доступ к элементам — двойные квадратные
скобки
МММ2[0][0] = 33
МММ2[1][4] = 55
ВыводСтроки "МММ2[0][0]="+МММ2[0][0]
ВыводСтроки "МММ2[1][4]="+МММ2[1][4]
// Инициализатор: каждый вложенный массив
создаётся явно
МММ2{
Новый Целое[4]{4,5,6,7,8},
Новый Целое[4]{41,52,63,74,85}
}
Для Инд1 = 0 По 1
Для Инд4 = 0
По 4
ВыводСтроки ""+МММ2[Инд1][Инд4]+" "+Инд1+"
"+Инд4
КонецЦикла
КонецЦикла
Обратите внимание: при инициализации каждый вложенный массив
задаётся явно через Новый Целое[4]{...}. Вложенные фигурные
скобки без оператора Новый для массивов массивов не работают — это
принципиальное отличие от инициализации обычных многомерных массивов.
Комбинированные массивы массивов: Целое[][,][]
Самое интересное — комбинировать разные типы вложенности. Рассмотрим объявление:
Перем МММ3 тип Целое[][,][]
= Новый Целое[1][2,3][4]
Читается это справа налево и означает трёхуровневую структуру:
Целое[][,][]— внешний массив из элементов типаЦелое[,][];Целое[,][]— прямоугольный двумерный массив, каждый элемент которого —Целое[];Целое[]— обычный одномерный массив целых.
Создание Новый Целое[1][2,3][4] означает: внешний
массив из 2 элементов; каждый — двумерный массив размером 3×4; каждый элемент
внутри — одномерный массив из 5 целых.
Доступ к элементам идёт через чередование обычных и «многомерных» индексаторов:
// Проверим типы на каждом уровне
вложенности
Для Инд1
= 0 По 1
ВыводСтроки ""+ТипЗнч(МММ3[Инд1])+" "+Инд1
Для Инд2
= 0 По 2
Для Инд3
= 0 По 3
ВыводСтроки ""+ТипЗнч(МММ3[Инд1][Инд2,Инд3])
+" "+Инд1+" "+Инд2+" "+Инд3
Для Инд4
= 0 По 4
ВыводСтроки ""+ТипЗнч(МММ3[Инд1][Инд2,Инд3][Инд4])
+" "+Инд1+"
"+Инд2+" "+Инд3+" "+Инд4
КонецЦикла
КонецЦикла
КонецЦикла
КонецЦикла
// Запись значений
МММ3[0][0,0][0] = 33
МММ3[1][2,3][4] = 55
ВыводСтроки "МММ3[0][0,0][0]="+МММ3[0][0,0][0]
ВыводСтроки "МММ3[1][2,3][4]="+МММ3[1][2,3][4]
Инициализатор такого «трёхуровневого» массива выглядит
громоздко, но вполне логично: каждый промежуточный уровень описывается своим
оператором Новый с явными размерами и вложенными фигурными
скобками:
МММ3{
Новый Целое[2,3][4]{
{Новый Целое[4]{14,15,16,17,18},
Новый Целое[4]{24,25,26,27,28},
Новый Целое[4]{34,35,36,37,38},
Новый Целое[4]{44,45,46,47,48}
},
{Новый Целое[4]{54,55,56,57,58},
Новый Целое[4]{64,65,66,67,68},
Новый Целое[4]{74,75,76,77,78},
Новый Целое[4]{84,85,86,87,88}
},
{Новый Целое[4]{94,95,96,97,98},
Новый Целое[4]{114,115,116,117,118},
Новый Целое[4]{224,225,226,227,228},
Новый Целое[4]{334,335,336,337,338}
}
},
Новый Целое[2,3][4]{
{Новый Целое[4]{444,445,446,447,448},
Новый Целое[4]{554,555,556,557,558},
Новый Целое[4]{664,665,666,667,668},
Новый Целое[4]{774,775,776,777,778}
},
{Новый Целое[4]{884,885,886,887,888},
Новый Целое[4]{994,995,996,997,998},
Новый Целое[4]{1114,1115,1116,1117,1118},
Новый Целое[4]{2224,2225,2226,2227,2228}
},
{Новый Целое[4]{3334,3335,3336,3337,3338},
Новый Целое[4]{4444,4445,4446,4447,4448},
Новый Целое[4]{5554,5555,5556,5557,5558},
Новый Целое[4]{6664,6665,6666,6667,6668}
}
}
}
// Обход всех четырёх измерений
Для Инд1
= 0 По 1
Для Инд2 = 0
По 2
Для Инд3
= 0 По 3
Для Инд4
= 0 По 4
ВыводСтроки ""+МММ3[Инд1][Инд2,Инд3][Инд4]
+" "+Инд1+"
"+Инд2+" "+Инд3+" "+Инд4
КонецЦикла
КонецЦикла
КонецЦикла
КонецЦикла
Как читать описание типа массива массивов
Описание типа многоуровневого массива в Перфолента.Net
читается справа налево. Пустые скобки [] — это одномерный массив; [,]
— прямоугольный двумерный; [,,] — трёхмерный и т. д.
|
Тип |
Что означает |
|
|
одномерный массив целых |
|
|
двумерный массив целых |
|
|
массив массивов целых |
|
|
массив двумерных массивов целых |
|
|
массив двумерных массивов, элементы которых — одномерные массивы целых |
Практическое правило: при создании через Новый
сначала указывается размер первого уровня, затем в квадратных скобках — размеры
вложенного многомерного уровня, затем — размеры следующего и так до самого
нижнего. Например, Новый Целое[1][2,3][4] создаёт 2 внешних
элемента, каждый — матрицу 3×4, каждый её элемент — массив из 5 целых.
Заключение
Многомерные массивы и массивы массивов в языке
Перфолента.Net предоставляют мощные возможности для работы с табличными
и многомерными данными. Язык поддерживает как обычные многомерные массивы, так
и массивы массивов произвольной вложенности, включая комбинированные типы вида Целое[][,][].
Основные возможности включают:
- Объявление массивов любой размерности и вложенности;
- Инициализацию при создании и заполнение существующих массивов;
- Изменение размера (с ограничением на последнюю размерность);
- Очистку и удаление массивов.
При работе с массивами массивов помните: каждый вложенный
массив — это отдельный объект, который нужно создать явно, а описание типа вида
Целое[][,][]
читается справа налево.
Сергей Рогаткин
К началу статьи