Имя: Пароль:
1C
1С v8
Рекурсия зацикливается
0 dGU
 
31.01.12
16:15
Процедура КнопкаВыполнитьНажатие(Кнопка)
   
   Объект = ТребованиеНакладная.ПолучитьОбъект();
   
   Движение = Объет.Движения.Хозрасчетный;
   Движение.Прочитать();
   Хозрасчетный = Движение.Выгрузить();
   
   Проверить(Хозрасчетный, Хозрасчетный.Скопировать())    
   
КонецПроцедуры

Процедура Проверить(Хозрасчетный, Хозрасчетный1)
   
   Для Каждого Стр Из Хозрасчетный Цикл
       НайденнаяСтрока = Хозрасчетный1.Найти(Стр.СчетДт, "СчетДт");
       Если НайденнаяСтрока <> Неопределено Тогда
           Хозрасчетный .Удалить(Стр);
           Хозрасчетный1.Удалить(НайденнаяСтрока);
           ПроверитьРегистры(Хозрасчетный, Хозрасчетный1);
       КонецЕсли;
   КонецЦикла;    
   
   Если ТаблицаДвиженийРегистров.Количество() = 0 И ТаблицаДвиженийРегистровКОМОбъект.Количество() = 0 Тогда
       Сообщить("1");    
   КонецЕсли;
   
КонецПроцедуры

Выше приведен пример обработки, которая "зацикливает рекурсию", по непонятной причине.
После выхода из цикла и вывода сообщения, снова запускается процедура.  
В чем подвох?
1 Alex S D
 
31.01.12
16:15
ПроверитьРегистры а это че такое
2 DmitrO
 
31.01.12
16:16
Когда перебираешь коллекцию циклом Для каждого нельзя изменять ее состав.
3 Guk
 
31.01.12
16:16
а выход из рекурсии Пушкин делать будет?...
4 Guk
 
31.01.12
16:19
кстати, в приведенном коде рекурсии не обнаружено...
5 Reset
 
31.01.12
16:20
А где здесь рекурсия? И что за "ПроверитьРегистры"?
6 dGU
 
31.01.12
16:32
Пардон код следующий:

(3) Выход из рекурсии происходит когда не выполняется условие "Если..."

Процедура КнопкаВыполнитьНажатие(Кнопка)
   
   Объект = ТребованиеНакладная.ПолучитьОбъект();
   
   Движение = Объет.Движения.Хозрасчетный;
   Движение.Прочитать();
   Хозрасчетный = Движение.Выгрузить();
   
   Проверить(Хозрасчетный, Хозрасчетный.Скопировать())    
   
КонецПроцедуры

Процедура Проверить(Хозрасчетный, Хозрасчетный1)
   
   Для Каждого Стр Из Хозрасчетный Цикл
       НайденнаяСтрока = Хозрасчетный1.Найти(Стр.СчетДт, "СчетДт");
       Если НайденнаяСтрока <> Неопределено Тогда
           Хозрасчетный .Удалить(Стр);
           Хозрасчетный1.Удалить(НайденнаяСтрока);
           Проверить(Хозрасчетный, Хозрасчетный1);
       КонецЕсли;
   КонецЦикла;    
   
   Если ТаблицаДвиженийРегистров.Количество() = 0 И ТаблицаДвиженийРегистровКОМОбъект.Количество() = 0 Тогда
       Сообщить("1");    
   КонецЕсли;
   
КонецПроцедуры
7 hhhh
 
31.01.12
16:38
(6) движения хочешь почистить. Втот так тогда

Процедура КнопкаВыполнитьНажатие(Кнопка)
   
   Объект = ТребованиеНакладная.ПолучитьОбъект();
   
   Движение = Объект.Движения.Хозрасчетный;
   Движение.Прочитать();
   Хозрасчетный = Движение.Выгрузить();
   Хозрасчетный.Очистить();
     
КонецПроцедуры

то же самое получится.
8 Rie
 
31.01.12
16:41
(6) Удалять внутри такой итерации - несколько неизящно, IMHO.
Да и, не закончив работу одного итератора, запускать на том же объекте ещё один, затем ещё и ещё... Тем паче, что рекурсия тут несколько неестественно смотрится.
9 dGU
 
31.01.12
16:41
:) спасибо, за ответ но вопрос актуален.
Если прогнать обработку в отладчике, после того как обе таблицы очищены выводиться сообщение. Затем заново запускается процедура.
10 kosts
 
31.01.12
16:43
(6) Код полностью переписать.

Рекурсия совершенно не нужна.
Удаление элементов в коллекции в цикле по этой же коллекции - результат не предсказуем.

думаю можно так сделать (грубо).


Процедура Проверить(Хозрасчетный, Хозрасчетный1)
   ~Метка:;
   Для Каждого Стр Из Хозрасчетный Цикл
       НайденнаяСтрока = Хозрасчетный1.Найти(Стр.СчетДт, "СчетДт");
       Если НайденнаяСтрока <> Неопределено Тогда
           Хозрасчетный .Удалить(Стр);
           Хозрасчетный1.Удалить(НайденнаяСтрока);
           Перейти ~Метка;
       КонецЕсли;
   КонецЦикла;    
   
   Если ТаблицаДвиженийРегистров.Количество() = 0 И ТаблицаДвиженийРегистровКОМОбъект.Количество() = 0 Тогда
       Сообщить("1");    
   КонецЕсли;
   
КонецПроцедуры
11 dGU
 
31.01.12
16:46
Спасибо, такой вариант конечно рассматривался, просто интересно почему рекурсия так работает, точнее вызывается уже после выхода из цикла.
12 Rie
 
31.01.12
16:47
(9) Обе таблицы очищены у тебя на самой-самой большой глубине рекурсии. Потом ты выходишь из _последнего_ вызова и - опаньки! - возвращаешься в предыдущий. Который продолжает свой цикл как ни в чём ни бывало. И т.д.
13 kosts
 
31.01.12
16:48
(11) Может "прервать" не хватает...


Процедура Проверить(Хозрасчетный, Хозрасчетный1)
   
   Для Каждого Стр Из Хозрасчетный Цикл
       НайденнаяСтрока = Хозрасчетный1.Найти(Стр.СчетДт, "СчетДт");
       Если НайденнаяСтрока <> Неопределено Тогда
           Хозрасчетный .Удалить(Стр);
           Хозрасчетный1.Удалить(НайденнаяСтрока);
           Проверить(Хозрасчетный, Хозрасчетный1);
Прервать;
       КонецЕсли;
   КонецЦикла;    
   
   Если ТаблицаДвиженийРегистров.Количество() = 0 И ТаблицаДвиженийРегистровКОМОбъект.Количество() = 0 Тогда
       Сообщить("1");    
   КонецЕсли;
   
КонецПроцедуры
14 Ненавижу 1С
 
гуру
31.01.12
16:49
еще раз танкисту:

Для Каждого Стр Из Хозрасчетный Цикл
       ...
           Хозрасчетный .Удалить(Стр); //Ошибка: При обходе коллекции "Для каждого" коллекцию изменять нельзя!
       ...
КонецЦикла;
15 Rie
 
31.01.12
16:49
(11) Выгрузи свои наборы записей в таблицы значений, сделай с ними всё, что требуется (по человечески, без ненужной рекурсии в циклах с модицифируемым объектом итерации), загрузи обратно наборы записей - и будет счастье.
16 Ненавижу 1С
 
гуру
31.01.12
16:49
(10) ипануться
17 kosts
 
31.01.12
16:51
(16) И не говори... :-)
18 Reset
 
31.01.12
16:51
(10) Приведенный код замечателен тем, что несовпадающие строки (для надежности!) ищутся по нескольку раз. Наглядное, правильное решение, удачно можно использовать в холиварах про goto.
19 dGU
 
31.01.12
16:51
(15) Спасибо вроде бы я понял, но (16) почему //Ошибка: При обходе коллекции "Для каждого" коллекцию изменять нельзя,почему нельзя менять-то?
20 GROOVY
 
31.01.12
16:53
(19) Итератор с ума сходит просто.
21 Ненавижу 1С
 
гуру
31.01.12
16:55
(19) потому что это плохо и НЕ православно, более того в C# даже будет ран-тайм, 1С просто было лень делать такие проверки
22 Rie
 
31.01.12
16:55
(19) Не знаю, как писали итератор авторы 1С 8.2, но они явно не предполагали такого его использования и не перестраховались на случай подобных извратов.
23 napagokc
 
31.01.12
16:56
Объект = ТребованиеНакладная.ПолучитьОбъект();
   
   Движение = Объет.Движения.Хозрасчетный;

во второй строчке опечатка или так и задумано "Объет"? (пропущена буква "к")
24 dGU
 
31.01.12
16:57
задумано чтобы всех ввести в заблуждение
25 kosts
 
31.01.12
17:01
26 napagokc
 
31.01.12
17:07
вопрос-то актуален? Если я не ошибаюсь, то тут идет банальная ошибка с обходом списка по циклу, при удалении строк этого списка. Если уж удаляешь элементы списка в цикле по этому списку, то обход нужно делать с конца списка на начало. Это стандартное правило для всех языков. Тут же идет неявная индексация с первого элемента до последнего. Вот и фигня получается. Думаю, в этом дело
27 acsent
 
31.01.12
17:11
юзай найтистроки
28 dGU
 
01.02.12
13:47
Всем спасибо. Думаю вопрос исчерпан.
2 + 2 = 3.9999999999999999999999999999999...