При разработке алгоритмов обработки данных в 1С часто возникает задача разделить коллекцию строк на части, например, получить первые N записей или ровно половину таблицы значений во вторую независимую таблицу. Разберем особенности работы с коллекциями строк в платформе 1С:Предприятие 8, типичные ошибки при выборе методов и наиболее эффективные варианты решения этой задачи.
Прежде чем приступать к коду, выясним принципиальную разницу между объектами платформы: методом Выгрузить обладает объект ТабличнаяЧасть (он формирует таблицу значений из выбранных строк табличной части объекта или документа). Если же мы работаем с объектом ТаблицаЗначений, то у него нет метода Выгрузить — для аналогичной операции используется встроенный метод Скопировать.
Рассмотрим основной и самый быстрый способ получения выборки строк. Метод Скопировать у объекта ТаблицаЗначений принимает два необязательных параметра: массив исходных строк и список колонок. Если передать массив строк, платформа создаст точную копию таблицы с аналогичной структурой колонок и заполнит ее указанными элементами.
Разберем по шагам, как скопировать первую половину строк:
СтрокаТаблицыЗначений из первой половины исходной таблицы.Скопировать, передав подготовленный массив.Посмотрим на пример программного кода:
КоличествоВсего = ИсходнаяТЗ.Количество();
КоличествоПоловина = Цел(КоличествоВсего / 2);
МассивСтрок = Новый Массив;
Для Счетчик = 0 По КоличествоПоловина - 1 Цикл
МассивСтрок.Добавить(ИсходнаяТЗ[Счетчик]);
КонецЦикла;
ВтораяТЗ = ИсходнаяТЗ.Скопировать(МассивСтрок);
Важный момент: в массив необходимо добавлять именно сами строки коллекции (элементы типа СтрокаТаблицыЗначений), а не их числовые индексы. Если выгрузка производится из реквизита формы или табличной части документа, синтаксис будет аналогичным, но вызов метода выполняется через Выгрузить:
// Для табличной части документа или справочника:
ВтораяТЗ = Объект.Товары.Выгрузить(МассивСтрок);
Проанализируем альтернативный подход, когда требуется не просто скопировать строки, но и, возможно, выполнить дополнительную обработку значений на лету. В этом случае мы сначала создаем пустую таблицу с точно такой же структурой колонок с помощью метода СкопироватьКолонки, а затем переносим значения свойств.
Посмотрим, как реализовать данный алгоритм:
ВтораяТЗ = ИсходнаяТЗ.СкопироватьКолонки();
КоличествоПоловина = Цел(ИсходнаяТЗ.Количество() / 2);
Для Счетчик = 0 По КоличествоПоловина - 1 Цикл
НоваяСтрока = ВтораяТЗ.Добавить();
ЗаполнитьЗначенияСвойств(НоваяСтрока, ИсходнаяТЗ[Счетчик]);
КонецЦикла;
Такой способ полностью переносит типы и наименования всех 15–20 колонок без ручного перечисления каждого поля, сохраняя исходную типизацию данных.
Иногда разработчики пытаются решить задачу через временные таблицы в запросе, передавая таблицу значений как параметр. Рассмотрим особенности и скрытые ограничения такого подхода:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ ПЕРВЫЕ 10
| *
|ИЗ
| &ИсходнаяТЗ КАК ИсходнаяТЗ";
Запрос.УстановитьПараметр("ИсходнаяТЗ", ИсходнаяТЗ);
ВтораяТЗ = Запрос.Выполнить().Выгрузить();
Обратим внимание на критические нюансы этого метода:
ОписаниеТипов. Если хотя бы одна колонка создана без указания типа данных, запрос завершится аварийно с ошибкой типизации.ВЫБРАТЬ ПЕРВЫЕ без явного указания директивы УПОРЯДОЧИТЬ ПО не гарантирует, что в выборку попадут именно первые строки в порядке их следования в таблице. Механизм СУБД рассматривает строки во временной таблице как неупорядоченное множество, поэтому без добавления колонки-индекса результат может отличаться от исходного порядка.Если исходная таблица значений в дальнейшем коде больше не требуется в исходном виде, можно обойтись без создания второго объекта и сэкономить оперативную память, просто удалив ненужные строки.
Разберем реализацию усечения. Важно: удаление строк из коллекции по индексу всегда следует выполнять с конца таблицы к началу (с шагом назад), чтобы индексы оставшихся элементов не смещались во время итераций:
ВсегоСтрок = ИсходнаяТЗ.Количество();
ГраницаОтсечения = Цел(ВсегоСтрок / 2);
Для Счетчик = ВсегоСтрок - 1 По ГраницаОтсечения Убыв Цикл
ИсходнаяТЗ.Удалить(Счетчик);
КонецЦикла;
Напомним, что объект ТаблицаЗначений является чисто серверным типом данных и недоступен на тонком клиенте и веб-клиенте в управляемом приложении. Все манипуляции по расчету половины строк, заполнению массивов и копированию должны производиться в процедурах и функциях с директивами &НаСервере, &НаСервереБезКонтекста или в модулях объектов и общих модулях.