В процессе разработки на платформе 1С:Предприятие 8 часто возникает задача обработки больших массивов данных в оперативной памяти. Одной из типичных ситуаций является работа с таблицами значений (ТЗ), когда нам необходимо найти определенные строки, проанализировать их и внести корректировки — например, при поиске и устранении пересортов по характеристикам или сериям номенклатуры. В этой статье мы подробно разберем, как работает механизм ссылок при поиске строк, и научимся эффективно управлять данными в ТаблицеЗначений.
Разберем фундаментальный вопрос, который часто возникает у начинающих и даже опытных разработчиков: если мы получаем массив строк с помощью метода НайтиСтроки(), будут ли изменения в этом массиве отражаться в исходной таблице? Рассмотрим ситуацию подробнее.
В 1С объекты коллекций, такие как строки таблицы значений, передаются и обрабатываются по ссылке. Когда вы вызываете метод НайтиСтроки(), платформа не создает копии данных. Она формирует массив, элементами которого являются ссылки на конкретные объекты — СтрокаТаблицыЗначений, уже существующие в вашей исходной ТЗ. Это означает, что любое изменение колонки в элементе массива мгновенно «зеркалируется» в исходной таблице.
Рассмотрим на примере:
// Предположим, у нас есть ТЗ с остатками
НайденныеСтроки = ТЗ_Остатки.НайтиСтроки(ПараметрыОтбора);
Для Каждого СтрокаМассива Из НайденныеСтроки Цикл
// Изменяя значение здесь, мы меняем его прямо в ТЗ_Остатки
СтрокаМассива.Количество = СтрокаМассива.Количество - 10;
КонецЦикла;
Проанализируем это поведение: такая архитектура крайне эффективна с точки зрения использования памяти. Нам не нужно заново записывать измененные строки в таблицу или искать их индексы для обновления — прямая работа с объектом строки экономит ресурсы сервера и время выполнения кода.
Пересорт — это ситуация, когда по одной номенклатуре (с учетом серии или характеристики) фактический остаток не совпадает с учетным, но общая сумма остатков может сходиться. Для решения этой задачи нам нужно сравнить две таблицы (например, «Учетные данные» и «Фактические данные») и «перетасовать» количества.
Разберем алгоритм поиска и корректировки, используя метод НайтиСтроки():
Рассмотрим пример кода, реализующий подобную логику:
ПараметрыОтбора = Новый Структура;
ПараметрыОтбора.Вставить("Номенклатура", ТекущаяНоменклатура);
ПараметрыОтбора.Вставить("Серия", ТекущаяСерия);
// Получаем массив ссылок на строки исходной таблицы
НайденныеСтроки = ТЗПоСкладу.НайтиСтроки(ПараметрыОтбора);
Если НайденныеСтроки.Количество() > 0 Тогда
Для Каждого СтрокаИзМассива Из НайденныеСтроки Цикл
// Проверяем условие пересорта
Если СтрокаИзМассива.ОстатокВБазе <> СтрокаИзМассива.ОстатокПравильный Тогда
// Прямое изменение данных в исходной ТЗ через ссылку
СтрокаИзМассива.Разница = СтрокаИзМассива.ОстатокПравильный - СтрокаИзМассива.ОстатокВБазе;
// Если нужно зафиксировать факт изменения для отчета
ДобавитьВЛогКорректировок(СтрокаИзМассива);
КонецЕсли;
КонецЦикла;
КонецЕсли;
Если ваша таблица содержит тысячи строк (например, более 5 000, как упоминалось в обсуждении), обычный метод НайтиСтроки() может начать работать медленно. Это происходит потому, что без специальной подготовки система вынуждена перебирать строки таблицы при каждом поиске (линейный поиск).
Чтобы ускорить этот процесс, проанализируем возможности индексации. В 1С 8.3 для объектов типа ТаблицаЗначений можно задать индексы. Индекс создает в памяти хеш-таблицу, которая позволяет методу НайтиСтроки() работать практически мгновенно.
Как добавить индекс:
// Добавляем индекс по полям, по которым чаще всего делаем отбор
ТЗПоСкладу.Индексы.Добавить("Номенклатура, Серия");
Важный нюанс: Индекс целесообразно добавлять один раз перед началом массовой обработки данных в цикле. Помните, что добавление индекса само по себе занимает время, поэтому для таблиц из 10-20 строк это не имеет смысла, но для «тяжелых» ТЗ это критически важный шаг.
Иногда при работе с массивом строк нам все же нужно знать порядковый номер строки в исходной таблице (например, для вывода сообщения пользователю или для связи с другими массивами). Поскольку элемент массива — это сам объект строки, мы можем легко получить его индекс с помощью метода исходной таблицы Индекс().
Выясним, как это реализовать:
Для Каждого СтрокаИзМассива Из НайденныеСтроки Цикл
НомерСтрокиВТЗ = ТЗПоСкладу.Индекс(СтрокаИзМассива);
Сообщить("Обработка строки номер: " + (НомерСтрокиВТЗ + 1));
// Выполняем тасовку данных
// ... логика переброски остатков ...
КонецЦикла;
Обратите внимание, что в 1С 8.x индексы начинаются с 0, в отличие от 1С 7.7, где работа велась с номерами строк, начинающимися с 1.
Когда мы нашли строки с излишками и строки с дефицитом в рамках одной номенклатуры, нам нужно «перекинуть» количество. Рассмотрим, как это сделать эффективно в один проход.
Проанализируем ситуацию: у нас есть «доноры» (где остаток больше нужного) и «реципиенты» (где остатка не хватает). Лучший способ — подготовить два массива внутри найденных строк и распределить разницу.
Такой подход позволяет не просто изменить цифры, а зафиксировать, «откуда и куда» ушел товар, что необходимо для формирования документов корректировки (например, «Оприходование» и «Списание» или «Корректировка регистров»).
Как упоминалось в исходной теме, работа часто ведется с виртуальными складами, где может быть «бардак» в данных. Посмотрим на важные советы по организации кода в таких условиях:
ТЗ.Удалить(Строка), ссылки в массиве могут стать невалидными. Лучше сначала очищать значения или помечать строки на удаление в отдельной колонке.НайденныеСтроки.Количество(), чтобы избежать лишних итераций.Таким образом, работа с массивом строк таблицы значений — это мощный инструмент. Главное помнить, что вы работаете с объектами-ссылками, что позволяет изменять исходную таблицу максимально быстро и удобно.