Как реализовать условие по комбинации нескольких строк в Таблице Значений

Программист 1С v8.3 (Управляемые формы) Управленческий учет
← На главную

В практике разработчика 1С часто возникает задача, когда алгоритм должен зависеть не от одной конкретной строки, а от набора данных во всей таблице. Типичный пример: если в заказе есть одновременно "Товар А" и "Товар Б", нужно распечатать особый вид договора. Обычный цикл Для каждого здесь не подходит, так как он анализирует строки изолированно. В этой статье мы подробно разберем, как эффективно обходить таблицу для поиска комбинаций и какие архитектурные подходы лучше всего использовать для решения подобных задач.

Метод 1. Использование вложенных циклов для поиска пар (сочетаний)

Рассмотрим ситуацию, когда нам нужно проверить все возможные пары строк в таблице. Если мы просто вложим один цикл в другой, мы столкнемся с проблемой избыточности: система будет проверять сначала пару (А, Б), а затем (Б, А). Чтобы оптимизировать процесс и перебирать только уникальные сочетания, во внутреннем цикле следует начинать отсчет со следующего индекса относительно внешнего.

Проанализируем пример кода, который позволяет перебрать все уникальные пары:


КоличествоСтрок = ТЗ.Количество();
Для Сч1 = 0 По КоличествоСтрок - 1 Цикл
    Строка1 = ТЗ[Сч1];
    
    // Внутренний цикл начинаем со следующего элемента
    Для Сч2 = Сч1 + 1 По КоличествоСтрок - 1 Цикл
        Строка2 = ТЗ[Сч2];
        
        // Логика проверки комбинации
        Если (Строка1.Номенклатура = ТоварА И Строка2.Номенклатура = ТоварБ) 
            ИЛИ (Строка1.Номенклатура = ТоварБ И Строка2.Номенклатура = ТоварА) Тогда
            // Действие для комбинации А+Б
        КонецЕсли;
    КонецЦикла;
КонецЦикла;

Этот метод хорош тем, что он математически точен и исключает сравнение строки самой с собой. Однако стоит помнить, что при большом количестве строк (более нескольких сотен) вложенные циклы могут существенно замедлить работу системы.

Метод 2. Проверка наличия через поиск в массиве или таблице

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

Разберем этот алгоритм по шагам:

  1. Выгружаем нужную колонку из ТаблицыЗначений в Массив.
  2. Проверяем вхождение первого ключевого товара.
  3. Если первый найден, проверяем вхождение второго.
  4. Если оба условия истинны — выполняем действие.

СписокТоваров = ТЗ.ВыгрузитьКолонку("Номенклатура");

ЕстьТоварА = СписокТоваров.Найти(СсылкаНаТоварА) <> Неопределено;
ЕстьТоварБ = СписокТоваров.Найти(СсылкаНаТоварБ) <> Неопределено;
ЕстьТоварВ = СписокТоваров.Найти(СсылкаНаТоварВ) <> Неопределено;

Если ЕстьТоварА И ЕстьТоварБ Тогда
    // Действие 2 (для комбинации А+В)
ИначеЕсли ЕстьТоварА Тогда
    // Действие 1 (только А)
КонецЕсли;

Важный нюанс: обратите внимание на порядок условий. Мы сначала проверяем самую сложную комбинацию (А+Б), и только потом одиночные значения. Это предотвращает ситуацию, когда «жадное» условие по одному товару сработает раньше, чем проверка их совокупности.

Метод 3. Использование двоичных масок (битовых флагов)

Если количество ключевых товаров фиксировано и невелико (например, до 10-15 позиций), мы можем применить изящный метод суммирования весов. Каждому интересующему нас товару присваивается число, являющееся степенью двойки (1, 2, 4, 8, 16...).

Выясним, как это работает на практике. Допустим:

Проанализируем алгоритм:


ИтоговаяМаска = 0;
Для Каждого Стр Из ТЗ Цикл
    Если Стр.Номенклатура = ТоварА Тогда
        ИтоговаяМаска = ИтоговаяМаска | 1; // Побитовое ИЛИ или просто +1, если уверены в уникальности строк
    ИначеЕсли Стр.Номенклатура = ТоварБ Тогда
        ИтоговаяМаска = ИтоговаяМаска | 2;
    ИначеЕсли Стр.Номенклатура = ТоварВ Тогда
        ИтоговаяМаска = ИтоговаяМаска | 4;
    КонецЕсли;
КонецЦикла;

// Теперь анализируем результат одним условием
Если ИтоговаяМаска = 3 Тогда // 1 + 2
    // В корзине только А и Б
ИначеЕсли ИтоговаяМаска = 7 Тогда // 1 + 2 + 4
    // В корзине А, Б и В одновременно
КонецЕсли;

Этот метод является самым быстрым, так как требует всего одного прохода по таблице значений, независимо от сложности проверяемых комбинаций.

Метод 4. Подготовка данных: Свертка и предварительная фильтрация

Перед тем как приступать к любому циклу по комбинациям, необходимо убедиться, что данные в таблице чистые. Если один и тот же "Товар А" встречается в таблице дважды (например, в разных строках с разной ценой), обычный цикл по индексам может выдать неверный результат или сработать лишний раз.

Рассмотрим обязательный этап предварительной обработки:


// Создаем копию, чтобы не испортить исходные данные для печати
ТЗ_Анализ = ТЗ.Скопировать();
// Оставляем только те колонки, которые влияют на логику договора
ТЗ_Анализ.Свернуть("Номенклатура"); 

Использование метода Свернуть гарантирует, что каждая позиция номенклатуры будет представлена в таблице ровно один раз, что упрощает логику ТЗ.Количество() и делает работу циклов предсказуемой.

Метод 5. Группировка на уровне запроса

Если данные в таблицу попадают из запроса, наиболее профессиональным подходом будет перенос логики комбинаций на уровень СУБД. Мы можем использовать временные таблицы для определения "варианта набора".

Разберем пример логики запроса:

  1. Выбираем все товары из документа во временную таблицу ВТ_Товары.
  2. Создаем таблицу ВТ_Правила, где описаны соответствия (Товар -> Группа).
  3. Соединяем эти таблицы и используем агрегатную функцию КОЛИЧЕСТВО(РАЗЛИЧНЫЕ ...).

Если запрос возвращает, что количество различных групп товаров в документе равно 3, и это именно группы А, Б и В — значит, условие выполнено. Такой подход позволяет изменять правила печати договоров без изменения программного кода, просто редактируя справочники или регистры сведений.

Резюме и рекомендации

Выбор конкретного метода зависит от масштаба вашей задачи:

Таким образом, задача "Если А+В Тогда Действие" решается переходом от построчного мышления к анализу всей совокупности данных. Проанализировав состав таблицы один раз, вы сможете легко определить нужный алгоритм печати или обработки документа.

← На главную