1с Рекурсия
По теме из базы знаний
- Рекурсия тестирования баз 1С. Когда однократного тестирования базы недостаточно
- Преобразование массива структур в дерево значений. Представление массива подчиненных друг другу "объектов" в иерархическом виде без использования рекурсии
- Создание в 1С 7.7 XML в формате EnterpriseData (универсальный формат обмена), версия 1.5. Инструкции и примеры переноса данных из устаревшей конфигурации 1С 7.7 в любую современную 1С 8.3, поддерживающую EnterpriseData, через Конвертацию данных 3
- Рекурсия для начинающих
- Глава 2. Как я написал (собрал с инфостарта) свой парсер сайта 1С Releases
Ответы
В избранное
Подписаться на ответы
Сортировка:
Древо развёрнутое
Свернуть все
(1) Поддерживаю (2). Вернее было написать "я начинаю только программировать в 1с".
Никакой рекурсии не нужно, простой цикл:
Никакой рекурсии не нужно, простой цикл:
ТекДата = ТекущаяДата();
ДатаГода = НачалоГода(ТекДата);
КонецГода = КонецГода(ТекДата);
КолВоСред = 0;
Пока ДатаГода < КонецГода Цикл
Если ДеньНедели(ДатаГода) = 3 Тогда
КолВоСред = КолВоСред + 1;
КонецЕсли;
ДатаГода = КонецДня(ДатаГода) + 1;
КонецЦикла;
Сообщить("Количество сред в " + Год(ТекДата) + " году: " + КолВоСред);
Показать
(5)
Ну или даже так
;-)
Хвостик = 0;
Если ДеньНедели(ТекущаяДата()) <= 3 И (ДеньНедели(КонецГода(ТекущаяДата())) >=3 ИЛИ ДеньНедели(КонецГода(ТекущаяДата())) < ДеньНедели(ТекущаяДата())) Тогда
Хвостик = 1;
КонецЕсли;
КоличествоСредДоКонцаГода = Цел((ДеньГода(ТекущаяДата()) - ДеньГода(КонецГода(ТекущаяДата())) + 1)/7) + Хвостик;
Ну или даже так
Функция КоличествоДнейНеделиВГоду(ДатаОтсчета, НомерДняНедели)
Хвостик = 0;
Если ДеньНедели(ДатаОтсчета) <= НомерДняНедели И (ДеньНедели(КонецГода(ДатаОтсчета)) >= НомерДняНедели ИЛИ ДеньНедели(КонецГода(ДатаОтсчета)) < ДеньНедели(ДатаОтсчета)) Тогда
Хвостик = 1;
КонецЕсли;
Результат = Цел((ДеньГода(ДатаОтсчета) - ДеньГода(КонецГода(ДатаОтсчета)) + 1)/7) + Хвостик;
Возврат Результат;
КонецФункции
Показать;-)
(6) Ну ладно, уговорили с рекурсией. Но это БРЕД!
Чудить так чудить:
// ДатаНачалаОтсчета - дата начала отсчета
// ДатаОкончанияОтсчета - конец года
// НомерДняНедели - для среды это 3
Функция КоличествоДнейНедели(ДатаНачалаОтсчета , ДатаОкончанияОтсчета, НомерДняНедели)
Если НачалоДня(ДатаНачалаОтсчета) > НачалоДня(ДатаОкончанияОтсчета) Тогда
Возврат 0;
Иначе
Бинго = ?(ДеньНедели(ДатаНачалаОтсчета) = НомерДняНедели, 1, 0);
Возврат Бинго + КоличествоДнейНедели(ДатаНачалаОтсчета + 86400, ДатаОкончанияОтсчета, НомерДняНедели);
КонецЕсли;
КонецФункции
ПоказатьЧудить так чудить:
Функция КоличествоДнейНедели(ДатаНачалаОтсчета , ДатаОкончанияОтсчета, НомерДняНедели)
Возврат ?(НачалоДня(ДатаНачалаОтсчета) > НачалоДня(ДатаОкончанияОтсчета), 0, ?(ДеньНедели(ДатаНачалаОтсчета) = НомерДняНедели, 1, 0) + КоличествоДнейНедели(ДатаНачалаОтсчета + 86400, ДатаОкончанияОтсчета, НомерДняНедели));
КонецФункции
Принцип рекурсии заключается в том, что входя в бесконечный цикл (итерацию), система сохраняет в памяти значения всех переменных и параметров функции, при выходе из цикла/итерации значения этих переменных восстанавливается. Таким образом рекурсию можно заменить на массивы (и цикл), куда сохранять значения всех необходимых переменных и восстанавливать их перед следующим циклом. Обычно это называется сохранением контекста.
Если с помощью цикла удалось порешать, то попробуйте пройтись с помощью рекурсии, например, по ДеревуЗначений. Каждый узел дерева имеет дочернии элементы, которые в свою очередь могут содержать свои дочернии элементы. Глубина ветки может быть большой и заранее её узнать нельзя. Основная ошибка при реализации рекурсии заключается в том, что разработчик не ставит ограничение на количество уровней (у SQL например это значение 100) при достижении которого надо выдать ошибку или прервать выполнение. Т.е. необходимо заранее определиться какая глубина вложенности может быть. В противном случае у вас закончится память на сохранении контекста. Бывает такое, когда где-то в глубине дерева один из элементов внезапно ссылается на одного из своих потомков и цикл входит в бесконечность.
Если с помощью цикла удалось порешать, то попробуйте пройтись с помощью рекурсии, например, по ДеревуЗначений. Каждый узел дерева имеет дочернии элементы, которые в свою очередь могут содержать свои дочернии элементы. Глубина ветки может быть большой и заранее её узнать нельзя. Основная ошибка при реализации рекурсии заключается в том, что разработчик не ставит ограничение на количество уровней (у SQL например это значение 100) при достижении которого надо выдать ошибку или прервать выполнение. Т.е. необходимо заранее определиться какая глубина вложенности может быть. В противном случае у вас закончится память на сохранении контекста. Бывает такое, когда где-то в глубине дерева один из элементов внезапно ссылается на одного из своих потомков и цикл входит в бесконечность.
&НаКлиенте
Процедура Команда1(Команда)
Кол = 0;
Сч = ТекущаяДата();
Пока КонецДня(Сч) <> КонецДня(КонецГода(ТекущаяДата())) Цикл
Если ДеньНедели(Сч)%3 = 0 И ДеньНедели(Сч)% 6 <> 0 Тогда
Кол = Кол + 1;
КонецЕсли;
Сч = Сч + 86400;
КонецЦикла;
Сообщить(Кол);
КонецПроцедуры
Процедура Команда1(Команда)
Кол = 0;
Сч = ТекущаяДата();
Пока КонецДня(Сч) <> КонецДня(КонецГода(ТекущаяДата())) Цикл
Если ДеньНедели(Сч)%3 = 0 И ДеньНедели(Сч)% 6 <> 0 Тогда
Кол = Кол + 1;
КонецЕсли;
Сч = Сч + 86400;
КонецЦикла;
Сообщить(Кол);
КонецПроцедуры
(18) А почему тогда не: Пока КонецДня(Сч) <> КонецДня(КонецГода(Сч)) Цикл ?
У нас же в задаче один год, переходящих не надо.
Хотя нет, не покатит, в цикле переход обязательно будет на следующий год.
Кстати, КонецДня в КонецДня(КонецГода()) лишний, КонецГода итак в конец дня время выставляет.
У нас же в задаче один год, переходящих не надо.
Хотя нет, не покатит, в цикле переход обязательно будет на следующий год.
Кстати, КонецДня в КонецДня(КонецГода()) лишний, КонецГода итак в конец дня время выставляет.
(21) С тем, что предлагал я в (19) не покатит, т.к. "Сч = Сч + 86400;" по любому приведет к переполнению года и получим бесконечный цикл. :)
С оригинальным условием "Пока КонецДня(Сч) <> КонецДня(КонецГода(ТекущаяДата())) Цикл" проблемы могут быть, только если запускать код под Новый год. Может выдать результат за текущий и наступивший новый год. :)
С оригинальным условием "Пока КонецДня(Сч) <> КонецДня(КонецГода(ТекущаяДата())) Цикл" проблемы могут быть, только если запускать код под Новый год. Может выдать результат за текущий и наступивший новый год. :)
(22) Именно поэтому не надо использовать КонецГода() от слова совсем. Надо в саму функцию уже передавать дату окончания расчета. И функция будет универсальная (можно передать и конец квартал и конец пятилетки), и переполнения не будет.
Вот как я выше в рекурсии сделал.
Вот как я выше в рекурсии сделал.
(24) Так в (14) нет функции, только цикл. А там преследовалась задача, судя по коду, минимум используемых переменных. Я из этого и исходил.
А так да, в условии должны быть установленные значения, а не вычисляемые, это и для производительности плохо. В моем примере с циклом так и есть.
А так да, в условии должны быть установленные значения, а не вычисляемые, это и для производительности плохо. В моем примере с циклом так и есть.
&НаКлиенте
Процедура Команда1(Команда)
Кол = 0;
Сч = ТекущаяДата();
Пока КонецДня(Сч) < КонецГода(ТекущаяДата()) Цикл
Если ДеньНедели(Сч) = 3 Тогда
Кол = Кол + 1;
КонецЕсли;
Сч = Сч + 86400;
КонецЦикла;
Сообщить(Кол);
КонецПроцедуры
Всё пучком и никуда не перескачет
Процедура Команда1(Команда)
Кол = 0;
Сч = ТекущаяДата();
Пока КонецДня(Сч) < КонецГода(ТекущаяДата()) Цикл
Если ДеньНедели(Сч) = 3 Тогда
Кол = Кол + 1;
КонецЕсли;
Сч = Сч + 86400;
КонецЦикла;
Сообщить(Кол);
КонецПроцедуры
Всё пучком и никуда не перескачет
Как ты советовал точно верный результат даст.
Процедура Команда1(Команда)
Кол = 0;
Сч = ТекущаяДата();
Пока КонецДня(Сч) <= КонецГода(Сч) Цикл
Если ДеньНедели(Сч) = 3 Тогда
Кол = Кол + 1;
КонецЕсли;
Сч = Сч + 86400;
КонецЦикла;
Сообщить(Кол);
КонецПроцедуры
Процедура Команда1(Команда)
Кол = 0;
Сч = ТекущаяДата();
Пока КонецДня(Сч) <= КонецГода(Сч) Цикл
Если ДеньНедели(Сч) = 3 Тогда
Кол = Кол + 1;
КонецЕсли;
Сч = Сч + 86400;
КонецЦикла;
Сообщить(Кол);
КонецПроцедуры
(29) Нет, не даст верный. Я же уже объяснял почему, сам вначале прокололся.
Проверь, что будет, когда Сч = 31.12.2020 (сколько-то времени), а дальше "Сч = Сч + 86400;" и на следующий цикл с условием "<= КонецГода(Сч)".
Не получится одну и ту же переменную и в левой, и в правой части условия использовать.
Проверь, что будет, когда Сч = 31.12.2020 (сколько-то времени), а дальше "Сч = Сч + 86400;" и на следующий цикл с условием "<= КонецГода(Сч)".
Не получится одну и ту же переменную и в левой, и в правой части условия использовать.
(33) получить номер недели по текущей дате , получить номер недели на конец года , высчитать разницу , единственное надо учесть на какой день попадает текущая дата - если этот например четверг то из результата надо вычесть единицу , ну и с концом года та же история , если конец года приходиться на вторник
Запутал ты меня)))
Процедура Команда1(Команда)
Кол = 0;
Сч = ТекущаяДата();
Конец = ТекущаяДата();
Пока КонецДня(Сч) <= КонецГода(Конец) Цикл
Если ДеньНедели(Сч) = 3 Тогда
Кол = Кол + 1;
КонецЕсли;
Сч = Сч + 86400;
КонецЦикла;
Сообщить(Кол);
КонецПроцедуры
Процедура Команда1(Команда)
Кол = 0;
Сч = ТекущаяДата();
Конец = ТекущаяДата();
Пока КонецДня(Сч) <= КонецГода(Конец) Цикл
Если ДеньНедели(Сч) = 3 Тогда
Кол = Кол + 1;
КонецЕсли;
Сч = Сч + 86400;
КонецЦикла;
Сообщить(Кол);
КонецПроцедуры
Вот, набросал универсальную функцию посчитывающую количество нужных дней в нужном периоде.
Функция КоличествоДнейНедели(Знач ДатаНачала, Знач ДатаОкончания, ДеньНедели)
ДатаНачала = НачалоДня(ДатаНачала);
ДатаОкончания = КонецДня(ДатаОкончания);
ДеньНеделиДатыНачала = ДеньНедели(ДатаНачала);
ДнейДоДняНедели = ДеньНедели - ДеньНеделиДатыНачала;
БлижайщийДеньНедели = ДатаНачала + 86400*(?(ДнейДоДняНедели<0,ДнейДоДняНедели+7, ДнейДоДняНедели));
КоличествоДнейНедели = Окр(0.5 + (ДатаОкончания - БлижайщийДеньНедели)/86400/7,0,РежимОкругления.Окр15как10);
Возврат КоличествоДнейНедели;
КонецФункции
Показать
Вакансии
Аналитик 1С / Бизнес-аналитик
Нижний Новгород
зарплата от 100 000 руб. до 250 000 руб.
Временный (на проект)
Нижний Новгород
зарплата от 100 000 руб. до 250 000 руб.
Временный (на проект)