Приветствуем вас, уважаемые начинающие разработчики! Сегодня мы разберем классическую задачу, с которой часто сталкиваются студенты профильных вузов или специалисты, проходящие собеседование на позицию младшего программиста 1С. Наша цель — не просто показать готовые строки кода, а подробно, шаг за шагом проанализировать теорию, разобрать типичные архитектурные ошибки новичков и написать оптимальное, отказоустойчивое решение согласно стандартам разработки фирмы «1С».
В этой статье мы изучим особенности работы с такими универсальными коллекциями значений, как Массив и Структура, разберем тонкости работы с датами и функциями форматирования, а также научимся агрегировать данные без использования тяжеловесных объектов базы данных.
Давайте проанализируем требования исходной задачи. Нам необходимо реализовать две части:
Для реализации первой части нам потребуется организовать цикл по дням месяца. Для второй части — выполнить обход уже заполненного массива и применить алгоритмы ветвления.
Рассмотрим подробнее фрагменты кода, которые часто пытаются написать начинающие программисты (в частности, те варианты, которые автор темы привел в сообщениях 28 и 29). Выясним, почему эти варианты содержат критические ошибки и как они скажутся на работе реальной программы.
Ошибка 1. Ручное изменение счетчика внутри цикла типа «Для»
В первой части своего решения автор написал следующую конструкцию:
Для Счетчик = Счетчик1 по чслКоличестовДней Цикл
// ... логика ...
Счетчик = Счетчик + 1;
КонецЦикла;
Проанализируем эту ситуацию. В языке 1С цикл Для ... По ... автоматически управляет переменной-счетчиком на каждой итерации. Попытка вручную изменять переменную Счетчик внутри тела цикла является грубейшей логической ошибкой. В лучшем случае платформа проигнорирует ваше ручное сложение при переходе на следующую итерацию, в худшем — это приведет к непредсказуемым пропускам шагов цикла или бесконечному зацикливанию алгоритма. Запомните: управлять шагом цикла вручную можно только в циклах типа Пока.
Ошибка 2. Локалезависимость и сравнение строк при определении дней недели
Для определения выходных дней автор использует следующее условие:
Если НашаСтруктура.ДеньНедели = "суббота" Или НашаСтруктура.ДеньНедели = "воскресенье" Тогда
Выясним причину, почему такой подход считается плохой практикой в профессиональной разработке. Функция Формат() с параметром ДФ=dddd возвращает строковое представление дня недели на языке текущей локализации операционной системы. Если база данных будет запущена на сервере с англоязычной операционной системой, функция вернет значения "Saturday" и "Sunday". В итоге ваше условие никогда не выполнится, а программа отработает некорректно. Также не стоит забывать про регистр букв: сравнение строки со значением с заглавной буквы (например, «Суббота») вернет ложь. Для определения выходных дней необходимо использовать числовые индексы дней недели.
Ошибка 3. Выход за область видимости переменных
Во второй части кода автор пытается обратиться к переменной НашаСтруктура, которая была объявлена в первой процедуре:
Если НашаСтруктура.ДеньНедели = "суббота" Тогда ...
В 1С переменные, объявленные внутри одной процедуры или функции, имеют локальную область видимости и уничтожаются сразу после завершения работы этой процедуры. Во второй процедуре (по кнопке) переменная НашаСтруктура будет равна Неопределено или вызовет ошибку компиляции «Переменная не определена». Для доступа к данным во второй части задачи необходимо обращаться исключительно к элементам ранее сохраненного массива.
Ошибка 4. Неявное сравнение разных типов данных
Посмотрим на следующую строку из попытки автора обработать массив:
Если ЭлМассива = чслМясоВВыходные Тогда
Здесь ЭлМассива — это очередной элемент нашего массива, то есть объект типа Структура. Переменная чслМясоВВыходные — это число. Попытка сравнить сложный объект (структуру) с числом напрямую приведет к ошибке времени выполнения. Чтобы получить значение, необходимо обращаться к конкретному свойству структуры по его ключу: ЭлМассива.Количество.
Ошибка 5. Избыточное использование Таблицы Значений
Использование объекта ТаблицаЗначений для решения этой задачи (как показано в сообщении 29) является классическим примером избыточного усложнения кода. Таблица значений — это тяжелый универсальный объект, предназначенный для работы со сложными реляционными структурами данных в оперативной памяти. Для простого подсчета сумм и количества элементов в массиве из 30 элементов создавать таблицу значений неэффективно. Достаточно использовать простые переменные-аккумуляторы в обычном цикле обхода массива.
Рассмотрим правильный, надежный и оптимизированный вариант решения первой части задачи. Мы будем использовать встроенные функции работы с датами, чтобы наш код не зависел от локализации системы и настроек региональных стандартов.
Для этого напишем следующий программный код:
// Определим период работы — текущий месяц
ДатаМесяца = НачалоМесяца(ТекущаяДата());
КоличествоДнейВМесяце = День(КонецМесяца(ДатаМесяца));
// Инициализируем массив для хранения структур
МассивМороженого = Новый Массив;
// Зададим условные объемы потребления мороженого
КолвоВБудни = 2; // Например, 2 порции в будний день
КолвоВВыходные = 5; // Например, 5 порций в выходной день
Для ЧислоМесяца = 1 По КоличествоДнейВМесяце Цикл
// Рассчитываем точную дату для текущего шага цикла
ТекущаяДатаДня = ДатаМесяца + (ЧислоМесяца - 1) * 86400; // 86400 — количество секунд в сутках
// Получаем номер дня недели (от 1 — понедельник, до 7 — воскресенье)
НомерДняНедели = ДеньНедели(ТекущаяДатаДня);
ЭтоВыходной = (НомерДняНедели = 6 Или НомерДняНедели = 7);
// Определяем количество мороженого с помощью тернарного оператора
КоличествоМороженого = ?(ЭтоВыходной, КолвоВВыходные, КолвоВБудни);
// Получаем локализованное название дня недели исключительно для вывода на экран
ИмяДняНедели = Формат(ТекущаяДатаДня, "ДФ=dddd");
// Создаем структуру и сразу заполняем ее конструктором (это быстрее, чем метод Добавить)
ДанныеДня = Новый Структура("ДеньНедели, ДеньМесяца, Количество",
ИмяДняНедели, ЧислоМесяца, КоличествоМороженого);
// Добавляем готовую структуру в массив
МассивМороженого.Добавить(ДанныеДня);
КонецЦикла;
// Выводим результаты в окно сообщений
Сообщить("--- Данные по потреблению мороженого за месяц ---");
Для Каждого Элемент Из МассивМороженого Цикл
// Используем современную функцию СтрШаблон для красивого форматирования строк
СтрокаВывода = СтрШаблон("%1 %2: %3", Элемент.ДеньМесяца, Элемент.ДеньНедели, Элемент.Количество);
Сообщить(СтрокаВывода);
КонецЦикла;
Разберем по шагам ключевые моменты этого алгоритма:
НачалоМесяца, КонецМесяца и День. Это позволяет коду автоматически адаптироваться под любой месяц года (28, 29, 30 или 31 день).(ЧислоМесяца - 1) * 86400. Это самый быстрый и надежный способ смещения даты в 1С.ДеньНедели() возвращает число от 1 до 7. Этот метод абсолютно надежен, так как он не зависит от языка интерфейса пользователя и операционной системы. Понедельник всегда будет равен 1, а воскресенье — 7.Добавить() для структуры, мы использовали конструктор: Новый Структура("ИмяКолонки1, ИмяКолонки2", Значение1, Значение2). Такой подход работает быстрее и делает код более лаконичным.СтрШаблон(). Она заменяет маркеры %1, %2 и т.д. на переданные значения. Это избавляет разработчика от долгой и некрасивой конкатенации строк через оператор «плюс» и автоматически преобразует числа в строку без лишних пробелов.Теперь перейдем ко второй части нашей задачи. Нам необходимо обойти созданный на первом шаге массив, проанализировать хранящиеся там данные и вывести статистику. Для этого мы напишем процедуру, которая будет вызываться при нажатии кнопки на форме.
Посмотрим на пример реализации этого алгоритма:
// Процедура-обработчик нажатия кнопки на форме
&НаКлиенте
Процедура РассчитатьПоказателиНажатие(Кнопка)
// В реальном приложении массив должен храниться в реквизите формы или передаваться как параметр.
// Предположим, что МассивМороженого — это переменная, доступная в контексте модуля.
Если МассивМороженого.Количество() = 0 Тогда
ПоказатьПредупреждение(, "Массив данных пуст! Сначала заполните массив.");
Возврат;
КонецЕсли;
// Инициализируем переменные для подсчета статистики
КоличествоБудней = 0;
СуммаБудней = 0;
КоличествоВыходных = 0;
СуммаВыходных = 0;
КоличествоСуббот = 0;
// Обходим массив структур в цикле
Для Каждого ЗаписьДня Из МассивМороженого Цикл
// Для безопасного текстового сравнения приведем строку дня недели к нижнему регистру
ДеньНеделиСтрокой = НРег(ЗаписьДня.ДеньНедели);
// Проверяем, является ли день выходным
Если ДеньНеделиСтрокой = "суббота" Или ДеньНеделиСтрокой = "воскресенье" Тогда
КоличествоВыходных = КоличествоВыходных + 1;
СуммаВыходные = СуммаВыходные + ЗаписьДня.Количество;
// Если это суббота, увеличиваем отдельный счетчик суббот
Если ДеньНеделиСтрокой = "суббота" Тогда
КоличествоСуббот = КоличествоСуббот + 1;
КонецЕсли;
Иначе // Если день рабочий (будний)
КоличествоБудней = КоличествоБудней + 1;
СуммаБудней = СуммаБудней + ЗаписьДня.Количество;
КонецЕсли;
КонецЦикла;
// Выводим полученные результаты пользователю
Сообщить("=== Результаты статистического анализа ===");
Сообщить(СтрШаблон("Будние дни: приемов мороженого — %1, съедено всего порций — %2",
КоличествоБудней, СуммаБудней));
Сообщить(СтрШаблон("Выходные дни: приемов мороженого — %1, съедено всего порций — %2",
КоличествоВыходных, СуммаВыходные));
Сообщить(СтрШаблон("Всего суббот в указанном периоде: %1", КоличествоСуббот));
КонецПроцедуры
Проанализируем особенности реализации этого алгоритма:
НРег() приводит все символы строки к нижнему (строчному) регистру. Это защищает ваш алгоритм от возможных различий в написании названий дней недели (например, если система вернет «Суббота» вместо «суббота»).Количество(). Если массив пуст, выполнение прерывается, что предотвращает появление ошибок в интерфейсе.Если вы хотите, чтобы ваш код соответствовал высшим стандартам разработки в среде «1С:Предприятие 8», обратите внимание на следующие рекомендации:
Произвольный, чтобы хранить коллекцию между серверными вызовами.СекундВСутках = 86400;. Это улучшает читаемость кода для других разработчиков.Мы подробно разобрали задачу работы с массивами и структурами в 1С. Теперь вы умеете правильно использовать эти коллекции, избегать типичных ошибок с областями видимости и типами данных, а также писать эффективный и быстродействующий код.