Столбец двумерного массива, таблицы значений и списка: доступ из кода 1С

· 9 мин

Содержание

Обратиться к колонке массива в 1С можно так: в двумерном массиве — Матрица[НомерСтроки][НомерКолонки], а всю колонку собрать циклом по строкам. В таблице значений колонку целиком отдаёт метод ВыгрузитьКолонку("ИмяКолонки") — он сразу возвращает обычный Массив.

Сложность в том, что «колонок» у самого типа Массив нет. Это одномерная коллекция. Колонка появляется, когда массив вложенный, когда данные лежат в таблице значений или когда речь о поле динамического списка на форме. Ниже — пять рабочих способов для каждого случая, с кодом для платформы 8.3.

Откуда у массива колонки: двумерный массив, таблица и список

Встроенный язык 1С знает несколько коллекций, и «колонка» в них устроена по-разному:

  • 🔢 Массив массивов. Каждый элемент внешнего массива — строка, внутри неё лежат значения. Колонка — это элементы с одним и тем же индексом во всех строках.
  • 📊 Таблица значений. Колонки здесь настоящие: у них есть имя, тип и заголовок. Они хранятся в коллекции Колонки.
  • 🧩 Массив структур. Строка — структура, колонка — ключ структуры. Частый результат разбора JSON или ответа веб-сервиса.
  • 🖥 Динамический список. Колонка — поле списка на управляемой форме. Обращение идёт к данным текущей или выделенной строки.

Индексация везде начинается с нуля. В массиве из 5 элементов последний индекс — 4, а Количество() вернёт 5. Эта разница — частая причина ошибки «за границами массива».

Структура данныхКак взять значениеКак взять всю колонку
Массив массивовМ[2][1]цикл по строкам
Массив (одномерный)М[3] или М.Получить(3)—
Таблица значенийСтрока.Сумма, Строка["Сумма"], Строка[0]ТЗ.ВыгрузитьКолонку("Сумма")
Табличная часть объектаСтрока.КоличествоОбъект.Товары.ВыгрузитьКолонку("Номенклатура")
Массив структурМ[0].Суммацикл по элементам
Динамический списокЭлементы.Список.ТекущиеДанные.Суммацикл по ВыделенныеСтроки

Способ 1. Индексы в двумерном массиве (массиве массивов)

Конструктор Новый Массив принимает несколько размерностей. Новый Массив(3, 4) создаёт внешний массив из трёх элементов, и каждый из них — массив из четырёх значений Неопределено.

Матрица = Новый Массив(3, 4);

// Заполним: значение = номер строки * 10 + номер колонки
Для НомерСтроки = 0 По 2 Цикл
	Для НомерКолонки = 0 По 3 Цикл
		Матрица[НомерСтроки][НомерКолонки] = НомерСтроки * 10 + НомерКолонки;
	КонецЦикла;
КонецЦикла;

Значение = Матрица[2][1]; // 21 — третья строка, вторая колонка

Первый индекс — строка, второй — колонка. Матрица.Количество() вернёт 3 (строк), Матрица[0].Количество() — 4 (колонок).

Как получить всю колонку

Отдельного метода нет, колонку собирают циклом. Удобно вынести это в функцию общего модуля:

Функция КолонкаМатрицы(Матрица, НомерКолонки) Экспорт

	Результат = Новый Массив;
	Для Каждого СтрокаМатрицы Из Матрица Цикл
		Если НомерКолонки < СтрокаМатрицы.Количество() Тогда
			Результат.Добавить(СтрокаМатрицы[НомерКолонки]);
		Иначе
			Результат.Добавить(Неопределено);
		КонецЕсли;
	КонецЦикла;
	Возврат Результат;

КонецФункции

Для матрицы выше КолонкаМатрицы(Матрица, 1) вернёт массив 1, 11, 21.

Проверка длины строки нужна потому, что вложенные массивы не обязаны быть одинаковыми. Если массив собирали вручную через Добавить(), в одной строке может оказаться 4 элемента, а в другой 3. Без проверки цикл упадёт на короткой строке.

Как записать значения в колонку

Запись — тот же цикл, только с присваиванием:

Для Каждого СтрокаМатрицы Из Матрица Цикл
	СтрокаМатрицы[3] = 0; // обнулить четвёртую колонку
КонецЦикла;

Если с двумерными данными приходится часто работать по колонкам — суммировать, искать, сортировать, — переложите их в таблицу значений. Там всё это делается одной строкой кода.

Способ 2. Колонки таблицы значений и ВыгрузитьКолонку

В таблице значений к колонке обращаются тремя путями:

  1. По имени через точку: Строка.Сумма. Самый читаемый вариант, но имя должно быть известно при написании кода.
  2. По имени в квадратных скобках: Строка["Сумма"]. Подходит, когда имя колонки лежит в переменной.
  3. По номеру: Строка[0]. Номер соответствует порядку колонок в коллекции Колонки.

Выгрузить колонку в массив

Метод ВыгрузитьКолонку возвращает массив значений колонки по всем строкам, в порядке строк:

Запрос = Новый Запрос;
Запрос.Текст =
	"ВЫБРАТЬ
	|	Контрагенты.Ссылка КАК Контрагент,
	|	Контрагенты.ИНН КАК ИНН
	|ИЗ
	|	Справочник.Контрагенты КАК Контрагенты";
Таблица = Запрос.Выполнить().Выгрузить();

МассивИНН = Таблица.ВыгрузитьКолонку("ИНН");

Параметром можно передать имя колонки, её номер или саму колонку из коллекции Колонки. Тот же метод есть у табличной части объекта: ДокументОбъект.Товары.ВыгрузитьКолонку("Номенклатура").

Обратная операция — ЗагрузитьКолонку(Массив, "ИмяКолонки"). Она раскладывает элементы массива по строкам таблицы: первый элемент в первую строку, второй во вторую. Готовьте массив той же длины, что и таблица.

Работа с коллекцией Колонки

Сама коллекция Колонки нужна, когда структура таблицы заранее неизвестна:

// Есть ли колонка
Если Таблица.Колонки.Найти("ИНН") <> Неопределено Тогда
	// колонка на месте
КонецЕсли;

// Обойти все колонки строки
Для Каждого Колонка Из Таблица.Колонки Цикл
	Сообщить(Колонка.Имя + ": " + Строка(Таблица[0][Колонка.Имя]));
КонецЦикла;

Таблица[0] — первая строка таблицы, к ней обращаются по индексу так же, как к элементу массива. Если таблица пустая, такая строка вызовет ошибку, поэтому сначала проверьте Таблица.Количество() > 0.

Для частых операций с колонкой у таблицы значений есть готовые методы:

  • ➕ Таблица.Итог("Сумма") — сумма числовой колонки.
  • 🔍 Таблица.НайтиСтроки(Новый Структура("ИНН", "7701234567")) — строки с нужным значением.
  • 🔃 Таблица.Сортировать("Сумма Убыв") — сортировка по колонке.
  • 🧮 Таблица.Свернуть("Контрагент", "Сумма") — группировка с суммированием.

Способ 3. Методы Получить и Установить у массива

У одномерного массива, кроме квадратных скобок, есть методы Получить(Индекс) и Установить(Индекс, Значение). Работают они так же, как индекс в скобках:

Ставки = Новый Массив;
Ставки.Добавить(0);
Ставки.Добавить(10);
Ставки.Добавить(20);

А = Ставки[2];          // 20
Б = Ставки.Получить(2); // тоже 20

Ставки.Установить(0, 5); // то же, что Ставки[0] = 5

Для двумерного массива методы комбинируются: Матрица.Получить(2).Получить(1) — тот же элемент, что Матрица[2][1].

Где Получить удобнее скобок:

  • 🔗 в цепочке вызовов, когда массив возвращает функция: ПолучитьДанные().Получить(0);
  • 📝 в коде, который должен одинаково читаться с методами других коллекций.

Ни скобки, ни Получить() не защищают от выхода за границу. Перед обращением по вычисленному индексу проверяйте его:

Если Индекс >= 0 И Индекс < Ставки.Количество() Тогда
	Значение = Ставки[Индекс];
КонецЕсли;

Способ 4. Колонка в массиве структур

Ответ HTTP-сервиса, прочитанный из JSON, или результат обработки часто приходит как массив структур. Колонка здесь — ключ:

Строки = Новый Массив;
Строки.Добавить(Новый Структура("Код, Сумма", "001", 1500));
Строки.Добавить(Новый Структура("Код, Сумма", "002", 2300));

Суммы = Новый Массив;
Для Каждого Элемент Из Строки Цикл
	Значение = Неопределено;
	Если Элемент.Свойство("Сумма", Значение) Тогда
		Суммы.Добавить(Значение);
	КонецЕсли;
КонецЦикла;
// Суммы: 1500, 2300

Метод Свойство с двумя параметрами сразу проверяет наличие ключа и кладёт значение во второй параметр. Обращение через точку Элемент.Сумма короче, но если ключа нет, код упадёт.

Если имя колонки передаётся строкой, используйте скобки: Элемент["Сумма"]. Для соответствия (Соответствие) запись такая же, но отсутствующий ключ вернёт Неопределено, а не ошибку.

Способ 5. Поле динамического списка на форме

В динамическом списке нет массива в памяти. Данные подгружаются порциями, и обращаться к «колонке» можно только через строки, которые сейчас есть на форме.

Текущая строка

&НаКлиенте
Процедура ПоказатьИНН(Команда)

	ТекущиеДанные = Элементы.Список.ТекущиеДанные;
	Если ТекущиеДанные = Неопределено Тогда
		Возврат;
	КонецЕсли;

	Сообщить(ТекущиеДанные.ИНН);

КонецПроцедуры

ТекущиеДанные возвращает Неопределено, когда список пуст или курсор не стоит на строке. Без этой проверки команда на пустом списке выдаст ошибку.

Колонка по выделенным строкам

Элементы.Список.ВыделенныеСтроки — массив ключей выделенных строк. Данные строки по ключу отдаёт метод таблицы формы ДанныеСтроки:

&НаКлиенте
Процедура СобратьИНН(Команда)

	МассивИНН = Новый Массив;
	Для Каждого Ключ Из Элементы.Список.ВыделенныеСтроки Цикл
		Если ТипЗнч(Ключ) = Тип("СтрокаГруппировкиДинамическогоСписка") Тогда
			Продолжить; // строка группировки, а не запись
		КонецЕсли;
		ДанныеСтроки = Элементы.Список.ДанныеСтроки(Ключ);
		Если ДанныеСтроки <> Неопределено Тогда
			МассивИНН.Добавить(ДанныеСтроки.ИНН);
		КонецЕсли;
	КонецЦикла;

КонецПроцедуры

Поле ИНН должно присутствовать в списке. Если колонку не вывели на форму, поле может не прийти в данные строки. Включите для него в настройках динамического списка признак «Использовать всегда» — тогда платформа будет выбирать его даже без колонки на форме.

Если пользователь выделил тысячи строк, разумнее передать массив ВыделенныеСтроки на сервер и получить нужные поля одним запросом с условием В (&Ссылки), а не перебирать данные строк на клиенте.

Какой способ доступа к колонке быстрее

Точные цифры зависят от сервера и объёма данных, но соотношение между способами стабильное.

ЗадачаБыстрый вариантМедленный вариант
Колонка таблицы целикомВыгрузитьКолонку()цикл по строкам с Добавить()
Сумма по колонкеИтог()цикл со сложением
Поиск строк по значениюНайтиСтроки() с индексомперебор с Если
Значение массива по индексуМ[i]М.Получить(i) — разница несущественна
Данные из базыполе в тексте запросаобращение через точку к реквизиту ссылки в цикле

Что даёт реальный выигрыш:

  1. Методы платформы вместо циклов. ВыгрузитьКолонку, Итог, Свернуть выполняются внутри платформы, а цикл на встроенном языке интерпретируется построчно. На таблице в сотни тысяч строк разница заметна.
  2. Индекс перед повторным поиском. Если по одной колонке ищете много раз, добавьте индекс: Таблица.Индексы.Добавить("ИНН"). Для разового поиска индекс не нужен — его построение само стоит времени.
  3. Поиск колонки вне цикла. Колонки.Найти() и разбор имени колонки делайте один раз до цикла, а не на каждой строке.
  4. Без обращений через точку к ссылкам. Строка.Контрагент.ИНН внутри цикла — это отдельное чтение из базы на каждую строку. Получите ИНН в запросе сразу.
  5. Перебор Для Каждого. Для обхода всех строк он читается проще цикла по индексу и не требует следить за границами.

Таблица значений существует только на сервере. Если колонку нужно показать или обработать на клиенте, выгрузите её в массив на сервере и верните массив — массив примитивных значений и ссылок между клиентом и сервером передаётся.

Ошибки при обращении к колонкам и как их найти

Сбои при работе с колонками обычно сводятся к пяти ситуациям.

Диагностика: выберите симптом

Ещё одна тонкость — изменение массива во время обхода. Если удаляете элементы, идите с конца, иначе индексы сдвинутся и часть элементов пропустится:

Для Сч = 1 По Ставки.Количество() Цикл
	Индекс = Ставки.Количество() - Сч;
	Если Ставки[Индекс] = 0 Тогда
		Ставки.Удалить(Индекс);
	КонецЕсли;
КонецЦикла;

Граница цикла вычисляется один раз при входе, а Ставки.Количество() - Сч пересчитывается на каждом шаге. После удаления элемента индексы оставшихся слева не меняются, поэтому обход доходит до нулевого элемента без пропусков.

Частые вопросы о колонках массивов в 1С

Можно ли создать массив сразу с тремя измерениями?
Да. Новый Массив(2, 3, 4) создаёт массив массивов массивов, обращение — М[1][2][3]. На практике больше двух измерений неудобно отлаживать.
Как узнать количество колонок в таблице значений?
Таблица.Колонки.Количество(). Имя колонки по номеру — Таблица.Колонки[0].Имя.
Как транспонировать двумерный массив — сделать колонки строками?
Создайте новый массив с размерами наоборот и в двойном цикле присвойте Новая[j][i] = Старая[i][j]. Встроенного метода для этого нет.
Чем ФиксированныйМассив отличается при чтении колонки?
Читать элементы можно так же, по индексу. Менять нельзя: методов Добавить и Установить у него нет.
Как получить колонку из списка значений?
СписокЗначений.ВыгрузитьЗначения() возвращает массив значений элементов списка.