1с Рекурсия

1. neponimashka 16.09.20 19:50 Сейчас в теме
По теме из базы знаний
Ответы
В избранное Подписаться на ответы Сортировка: Древо развёрнутое
Свернуть все
5. Release 16.09.20 20:22 Сейчас в теме
(1) Поддерживаю (2). Вернее было написать "я начинаю только программировать в 1с".
Никакой рекурсии не нужно, простой цикл:
ТекДата = ТекущаяДата();
ДатаГода = НачалоГода(ТекДата);
КонецГода = КонецГода(ТекДата);

КолВоСред = 0;

Пока ДатаГода < КонецГода Цикл
	Если ДеньНедели(ДатаГода) = 3 Тогда
		КолВоСред = КолВоСред + 1;
	КонецЕсли;
	
	ДатаГода = КонецДня(ДатаГода) + 1;
КонецЦикла;

Сообщить("Количество сред в " + Год(ТекДата) + " году: " + КолВоСред);
Показать
alex-l19041; neponimashka; +2 Ответить
7. neponimashka 16.09.20 20:32 Сейчас в теме
(5)Спасибо за решение, но через цикл я уже прорешала) хотелось именно на вызов функции самой себя посмотреть, как это вообще реализовывается, просто не совсем понятна работа с датами через данный способ ((
9. FatPanzer 16.09.20 20:37 Сейчас в теме
(5)
Хвостик = 0;
Если ДеньНедели(ТекущаяДата()) <= 3 И (ДеньНедели(КонецГода(ТекущаяДата())) >=3 ИЛИ ДеньНедели(КонецГода(ТекущаяДата())) < ДеньНедели(ТекущаяДата())) Тогда
	Хвостик = 1;
КонецЕсли;
КоличествоСредДоКонцаГода = Цел((ДеньГода(ТекущаяДата()) - ДеньГода(КонецГода(ТекущаяДата())) + 1)/7) + Хвостик;


Ну или даже так
Функция КоличествоДнейНеделиВГоду(ДатаОтсчета, НомерДняНедели)
	
	Хвостик = 0;
	Если ДеньНедели(ДатаОтсчета) <= НомерДняНедели И (ДеньНедели(КонецГода(ДатаОтсчета)) >= НомерДняНедели ИЛИ ДеньНедели(КонецГода(ДатаОтсчета)) < ДеньНедели(ДатаОтсчета)) Тогда
		Хвостик = 1;
	КонецЕсли;
	Результат = Цел((ДеньГода(ДатаОтсчета) - ДеньГода(КонецГода(ДатаОтсчета)) + 1)/7) + Хвостик;

	Возврат Результат;
	
КонецФункции
Показать

;-)
criptid; neponimashka; +2 Ответить
13. FatPanzer 16.09.20 21:17 Сейчас в теме
(9) Хотя нет, еще пару условий надо добавить.
8. Xershi 1474 16.09.20 20:35 Сейчас в теме
(1) решайте задачу циклом.Это будет оптимально.

Рекурсия это тот же цикл. Главное чтобы он был конечный.
В коде вызываете саму процедуру и все.
38. alex-l19041 8 17.09.20 10:13 Сейчас в теме
(1) "интересно" читать ответы к вопросу которого уже нет...
suepifanov; +1 Ответить
2. FatPanzer 16.09.20 20:07 Сейчас в теме
Боюсь, что вы просто не так понимаете термин "рекурсия". В данной задаче в рекурсии нет необходимости.
alex-l19041; Release; +2 Ответить
3. neponimashka 16.09.20 20:10 Сейчас в теме
(2)Нужно использовать в процедуре/функции вызов самой себя.
попробовала сделать так, но почему-то выводятся все недели
Прикрепленные файлы:
4. FatPanzer 16.09.20 20:21 Сейчас в теме
(3) Кому нужно? Повторюсь, в этой задаче нет необходимости в рекурсии.
farengeit00; +1 Ответить
6. neponimashka 16.09.20 20:24 Сейчас в теме
(4)Видела, что можно поиск даты осуществлять с помощью вызова самой себя функции/процедуры, хотелось написать код именно таким образом, потому что не совсем понимаю, как это реализововается с текущего дня, до конца года ;c
11. FatPanzer 16.09.20 20:43 Сейчас в теме
(6) Я в этой жизни тоже много извращений видел, но не все хочется пробовать. Да даже и пытаться понимать не хочется ))
neponimashka; +1 Ответить
12. FatPanzer 16.09.20 20:51 Сейчас в теме
(6) Ну ладно, уговорили с рекурсией. Но это БРЕД!

// ДатаНачалаОтсчета - дата начала отсчета
// ДатаОкончанияОтсчета - конец года
// НомерДняНедели - для среды это 3
Функция КоличествоДнейНедели(ДатаНачалаОтсчета , ДатаОкончанияОтсчета, НомерДняНедели)
	
	Если НачалоДня(ДатаНачалаОтсчета) > НачалоДня(ДатаОкончанияОтсчета) Тогда
		Возврат 0;
	Иначе
		Бинго = ?(ДеньНедели(ДатаНачалаОтсчета) = НомерДняНедели, 1, 0);
		Возврат Бинго + КоличествоДнейНедели(ДатаНачалаОтсчета + 86400, ДатаОкончанияОтсчета, НомерДняНедели);
	КонецЕсли;
	
КонецФункции
Показать

Чудить так чудить:
Функция КоличествоДнейНедели(ДатаНачалаОтсчета , ДатаОкончанияОтсчета, НомерДняНедели)
	
	Возврат ?(НачалоДня(ДатаНачалаОтсчета) > НачалоДня(ДатаОкончанияОтсчета), 0, ?(ДеньНедели(ДатаНачалаОтсчета) = НомерДняНедели, 1, 0) + КоличествоДнейНедели(ДатаНачалаОтсчета + 86400, ДатаОкончанияОтсчета, НомерДняНедели));
    
КонецФункции
10. PerlAmutor 129 16.09.20 20:39 Сейчас в теме
Принцип рекурсии заключается в том, что входя в бесконечный цикл (итерацию), система сохраняет в памяти значения всех переменных и параметров функции, при выходе из цикла/итерации значения этих переменных восстанавливается. Таким образом рекурсию можно заменить на массивы (и цикл), куда сохранять значения всех необходимых переменных и восстанавливать их перед следующим циклом. Обычно это называется сохранением контекста.

Если с помощью цикла удалось порешать, то попробуйте пройтись с помощью рекурсии, например, по ДеревуЗначений. Каждый узел дерева имеет дочернии элементы, которые в свою очередь могут содержать свои дочернии элементы. Глубина ветки может быть большой и заранее её узнать нельзя. Основная ошибка при реализации рекурсии заключается в том, что разработчик не ставит ограничение на количество уровней (у SQL например это значение 100) при достижении которого надо выдать ошибку или прервать выполнение. Т.е. необходимо заранее определиться какая глубина вложенности может быть. В противном случае у вас закончится память на сохранении контекста. Бывает такое, когда где-то в глубине дерева один из элементов внезапно ссылается на одного из своих потомков и цикл входит в бесконечность.
alex-l19041; criptid; FatPanzer; neponimashka; +4 Ответить
14. farengeit00 16.09.20 21:22 Сейчас в теме
&НаКлиенте
Процедура Команда1(Команда)
Кол = 0;
Сч = ТекущаяДата();
Пока КонецДня(Сч) <> КонецДня(КонецГода(ТекущаяДата())) Цикл

Если ДеньНедели(Сч)%3 = 0 И ДеньНедели(Сч)% 6 <> 0 Тогда
Кол = Кол + 1;
КонецЕсли;
Сч = Сч + 86400;
КонецЦикла;
Сообщить(Кол);
КонецПроцедуры
15. Release 16.09.20 21:29 Сейчас в теме
(14) Жесть какая! "Если ДеньНедели(Сч)%3 = 0 И ДеньНедели(Сч)% 6 <> 0 Тогда". Сударь знает толк в извращениях?
"Если ДеньНедели(Сч) = 3 Тогда", не?
criptid; farengeit00; +2 Ответить
16. farengeit00 16.09.20 21:31 Сейчас в теме
17. FatPanzer 16.09.20 21:40 Сейчас в теме
(14) Тут есть засада. Пока цикл считается - может измениться текущая дата ))))
18. farengeit00 16.09.20 21:49 Сейчас в теме
Может, но думаю не сегодня) А так
Конец = КонецДня(КонецГода(ТекущаяДата()));
Пока КонецДня(Сч) <> Конец...
19. Release 16.09.20 22:01 Сейчас в теме
(18) А почему тогда не: Пока КонецДня(Сч) <> КонецДня(КонецГода(Сч)) Цикл ?
У нас же в задаче один год, переходящих не надо.


Хотя нет, не покатит, в цикле переход обязательно будет на следующий год.
Кстати, КонецДня в КонецДня(КонецГода()) лишний, КонецГода итак в конец дня время выставляет.
20. farengeit00 16.09.20 22:07 Сейчас в теме
(19)А в чём разница то будет?
21. farengeit00 16.09.20 22:11 Сейчас в теме
22. Release 16.09.20 22:17 Сейчас в теме
(21) С тем, что предлагал я в (19) не покатит, т.к. "Сч = Сч + 86400;" по любому приведет к переполнению года и получим бесконечный цикл. :)
С оригинальным условием "Пока КонецДня(Сч) <> КонецДня(КонецГода(ТекущаяДата())) Цикл" проблемы могут быть, только если запускать код под Новый год. Может выдать результат за текущий и наступивший новый год. :)
24. FatPanzer 16.09.20 22:23 Сейчас в теме
(22) Именно поэтому не надо использовать КонецГода() от слова совсем. Надо в саму функцию уже передавать дату окончания расчета. И функция будет универсальная (можно передать и конец квартал и конец пятилетки), и переполнения не будет.
Вот как я выше в рекурсии сделал.
27. Release 16.09.20 22:33 Сейчас в теме
(24) Так в (14) нет функции, только цикл. А там преследовалась задача, судя по коду, минимум используемых переменных. Я из этого и исходил.
А так да, в условии должны быть установленные значения, а не вычисляемые, это и для производительности плохо. В моем примере с циклом так и есть.
23. farengeit00 16.09.20 22:19 Сейчас в теме
25. farengeit00 16.09.20 22:31 Сейчас в теме
&НаКлиенте
Процедура Команда1(Команда)
Кол = 0;
Сч = ТекущаяДата();
Пока КонецДня(Сч) < КонецГода(ТекущаяДата()) Цикл

Если ДеньНедели(Сч) = 3 Тогда
Кол = Кол + 1;
КонецЕсли;
Сч = Сч + 86400;
КонецЦикла;
Сообщить(Кол);
КонецПроцедуры

Всё пучком и никуда не перескачет
28. Release 16.09.20 22:35 Сейчас в теме
(25) Перескачет, но нужно ловить момент для этого. :)
26. farengeit00 16.09.20 22:32 Сейчас в теме
29. farengeit00 16.09.20 22:40 Сейчас в теме
Как ты советовал точно верный результат даст.
Процедура Команда1(Команда)
Кол = 0;
Сч = ТекущаяДата();
Пока КонецДня(Сч) <= КонецГода(Сч) Цикл

Если ДеньНедели(Сч) = 3 Тогда
Кол = Кол + 1;
КонецЕсли;
Сч = Сч + 86400;
КонецЦикла;
Сообщить(Кол);
КонецПроцедуры
30. Release 16.09.20 22:49 Сейчас в теме
(29) Нет, не даст верный. Я же уже объяснял почему, сам вначале прокололся.
Проверь, что будет, когда Сч = 31.12.2020 (сколько-то времени), а дальше "Сч = Сч + 86400;" и на следующий цикл с условием "<= КонецГода(Сч)".
Не получится одну и ту же переменную и в левой, и в правой части условия использовать.
31. vadim1011985 99 16.09.20 22:54 Сейчас в теме
Думаю эту задачу можно решить и без циклов
33. Release 16.09.20 22:56 Сейчас в теме
(31) По хорошему, нужно не думать, что что-то можно, а предлагать решение.
35. vadim1011985 99 16.09.20 23:01 Сейчас в теме
(33) получить номер недели по текущей дате , получить номер недели на конец года , высчитать разницу , единственное надо учесть на какой день попадает текущая дата - если этот например четверг то из результата надо вычесть единицу , ну и с концом года та же история , если конец года приходиться на вторник
36. Release 16.09.20 23:17 Сейчас в теме
(35) Как по мне, так легче было записать в виде кода, куда меньше текста:
КолСредВГоду = НеделяГода(КонецГода(ТекДата)) - ?(ДеньНедели(НачалоГода(ТекДата)) > 3, 1, 0) - ?(ДеньНедели(КонецГода(ТекДата)) > 3, 0, 1)

Как-то так, если за год.
32. farengeit00 16.09.20 22:55 Сейчас в теме
Запутал ты меня)))
Процедура Команда1(Команда)
Кол = 0;
Сч = ТекущаяДата();
Конец = ТекущаяДата();
Пока КонецДня(Сч) <= КонецГода(Конец) Цикл

Если ДеньНедели(Сч) = 3 Тогда
Кол = Кол + 1;
КонецЕсли;
Сч = Сч + 86400;
КонецЦикла;
Сообщить(Кол);
КонецПроцедуры
34. Release 16.09.20 23:01 Сейчас в теме
(32) Теперь более-менее верно, но, насколько я понял, задача была посчитать количество сред за весь год, а не с произвольной даты.
37. spacecraft 16.09.20 23:39 Сейчас в теме
Вот, набросал универсальную функцию посчитывающую количество нужных дней в нужном периоде.

Функция КоличествоДнейНедели(Знач ДатаНачала, Знач ДатаОкончания, ДеньНедели)
	ДатаНачала = НачалоДня(ДатаНачала);
	ДатаОкончания = КонецДня(ДатаОкончания);
	ДеньНеделиДатыНачала = ДеньНедели(ДатаНачала);
	ДнейДоДняНедели = ДеньНедели - ДеньНеделиДатыНачала;
	БлижайщийДеньНедели = ДатаНачала + 86400*(?(ДнейДоДняНедели<0,ДнейДоДняНедели+7, ДнейДоДняНедели));
	КоличествоДнейНедели = Окр(0.5 + (ДатаОкончания - БлижайщийДеньНедели)/86400/7,0,РежимОкругления.Окр15как10);
	Возврат КоличествоДнейНедели;
КонецФункции
Показать
39. пользователь 23.09.20 10:36
Сообщение было скрыто модератором.
...
Оставьте свое сообщение
Вакансии
1С аналитик
Москва
зарплата от 210 000 руб.
Полный день

Руководитель направления 1С
Москва
зарплата от 350 000 руб.
Полный день

1С Программист
Москва
зарплата от 180 000 руб.
Полный день

Программист 1С
Москва
зарплата от 180 000 руб. до 220 000 руб.
Полный день

Аналитик 1С / Бизнес-аналитик
Нижний Новгород
зарплата от 100 000 руб. до 250 000 руб.
Временный (на проект)