|
v7: Рекурсивная функция | ☑ | ||
---|---|---|---|---|
0
kloptula
18.10.12
✎
23:44
|
Есть вот такая функция, которая проверяет наличие строки в таблице значений и возвращает 1 в случае нахождения
Функция НайтиЗначениеВТаблице(ТЗ, Номенклатура, Серия, ЦенаПрод, НомерСтроки) // отфильтруем по дате поступления ТЗ.ПолучитьСтрокуПоНомеру(НомерСтроки); Если ТЗ.Номенклатура = Номенклатура Тогда Если (ТЗ.СерияНоменклатуры = Серия) и (ТЗ.ЦенаПрод = ЦенаПрод) и ((ТЗ.ДатаПартии - ДатаПоступления) < 0) Тогда Возврат 1; Иначе НайтиЗначениеВТаблице(ТЗ, Номенклатура, Серия, ЦенаПрод, НомерСтроки+1); КонецЕсли; Иначе Возврат 0; КонецЕсли; КонецФункции Так вот, эта функция возвращает не то, что должна. Например: нашлась строка с заданными реквизитами и функция должна вернуть 1, но если смотреть в отладчике, то сначала действительно возвращается 1, а вот потом рекурсия возвращается на предыдущий шаг и берет и возвращает 0. Че за х..ня не пойму ни как. Может сталкивался кто-нибудь с такой засадой |
|||
1
Лефмихалыч
18.10.12
✎
23:49
|
как вызываешь ее?
|
|||
2
HeroShima
18.10.12
✎
23:51
|
А зачем рекурсия?
|
|||
3
Лефмихалыч
18.10.12
✎
23:53
|
(2) видать холодно в кабинете, решил отопить путем нагрузки процессора
|
|||
4
kloptula
18.10.12
✎
23:54
|
(1) Вызываю вот так
Если НайтиЗначениеВТаблице(ТЗИтоговДоп, Запрос.Номенклатура, Запрос.Серия, Запрос.ЦенаПрод, НомСтр) = 0 Тогда Продолжить; КонецЕсли; |
|||
5
HeroShima
18.10.12
✎
23:54
|
(3) не иначе
|
|||
6
hhhh
18.10.12
✎
23:56
|
(4) но ведь она у тебя ничего и не возвращает. Юморист. До пятницы еще несколько минут.
|
|||
7
HeroShima
18.10.12
✎
23:56
|
(4) чувствуешь?
|
|||
8
kloptula
18.10.12
✎
23:58
|
(6) Если ты про "продолжить", то после этого идет вывод строки в отчет в цикле, а я вывод этой строки пропускаю.
|
|||
9
kloptula
19.10.12
✎
00:00
|
(6)
Пока Запрос.Группировка("Серия") = 1 Цикл // отфильтруем по дате поступления НомСтр = ""; Если ТЗИтоговДоп.НайтиЗначение(Запрос.Номенклатура, НомСтр, "Номенклатура") <> 0 Тогда Если НайтиЗначениеВТаблице(ТЗИтоговДоп, Запрос.Номенклатура, Запрос.Серия, Запрос.ЦенаПрод, НомСтр) = 0 Тогда Продолжить; КонецЕсли; Иначе Продолжить; КонецЕсли; ТЗ.НоваяСтрока(); ТЗ.Уровень = 0; ТЗ.ТекРасшифровка = ТМЦ; ТЗ.Родитель = ТМЦ.Родитель; ТЗ.ПечЕд = ?(ВидЕдиницы = 1,ТМЦ.ОсновнаяЕдиница, ТМЦ.БазоваяЕдиница); ТЗ.ПечТекстСтроки = ТМЦСтрока + ?(ТМЦ.МинОстаток=0,"",", мин. остаток = "+СокрЛП(глФРМКоличество(ТМЦ.МинОстаток,ТЗ.ПечЕд))); Если ВыводитьЗаказанный = 1 Тогда ТЗ.Заказано = Запрос.ЗаказаноКонОст; КонецЕсли; ЗаполнитьСтроку(ТЗ, Запрос, СписокСкладов, ВДокумент); КонецЦикла; |
|||
10
HeroShima
19.10.12
✎
00:00
|
(8) он про не возвращает, но тебе и на это там наплевать
|
|||
11
Лефмихалыч
19.10.12
✎
00:02
|
(9) *баный стыд... а не код. Как ты это говно читаешь?
|
|||
12
kloptula
19.10.12
✎
00:02
|
(10) Как правильно возвращать результат в рекурсивной функции в 1С?
|
|||
13
kloptula
19.10.12
✎
00:03
|
(11) Да это форум перековеркал. А код большей частью из ТиС типового
|
|||
14
hhhh
19.10.12
✎
00:04
|
(12) чему то присвоить. Переменной какой нибудь. АП то у тебя функция выполняется просто так, результат куда-то в небо передаешь.
|
|||
15
HeroShima
19.10.12
✎
00:05
|
(12) правильно возвращать значение по умолчанию вне условий, а затем ещё и проверять что вернули
|
|||
16
hhhh
19.10.12
✎
00:06
|
(14) вот тут например
Если (ТЗ.СерияНоменклатуры = Серия) и (ТЗ.ЦенаПрод = ЦенаПрод) и ((ТЗ.ДатаПартии - ДатаПоступления) < 0) Тогда Возврат 1; Иначе НайтиЗначениеВТаблице(ТЗ, Номенклатура, Серия, ЦенаПрод, НомерСтроки+1); КонецЕсли; вот где у тебя результат, ты говоришь, что 1. А он ведь в воздухе висит. Никуда потом не присваивается |
|||
17
kloptula
19.10.12
✎
00:08
|
(16) Вот так сделал. Один фиг тоже самое
Функция НайтиЗначениеВТаблице(ТЗ, Номенклатура, Серия, ЦенаПрод, НомерСтроки) // отфильтруем по дате поступления ТЗ.ПолучитьСтрокуПоНомеру(НомерСтроки); Если ТЗ.Номенклатура = Номенклатура Тогда Если (ТЗ.СерияНоменклатуры = Серия) и (ТЗ.ЦенаПрод = ЦенаПрод) и ((ТЗ.ДатаПартии - ДатаПоступления) < 0) Тогда Результат = 1; Иначе НайтиЗначениеВТаблице(ТЗ, Номенклатура, Серия, ЦенаПрод, НомерСтроки+1); КонецЕсли; Иначе Результат = 0; КонецЕсли; Возврат Результат; КонецФункции |
|||
18
kloptula
19.10.12
✎
00:09
|
Или глобальную переменную объявлять для возврата значения, но это же некрасиво
|
|||
19
HeroShima
19.10.12
✎
00:09
|
(17) Кому ты вернул результат? И убери рекурсию - за неё тут расстрелять нужно даже за работающую.
|
|||
20
Лефмихалыч
19.10.12
✎
00:10
|
Возврат НайтиЗначениеВТаблице(ТЗ, Номенклатура, Серия, ЦенаПрод, НомерСтроки+1);
блеать |
|||
21
Лефмихалыч
19.10.12
✎
00:10
|
но лучше разбег, стена, конец карьеры
|
|||
22
kloptula
19.10.12
✎
00:11
|
(20) Бл.. генитально
Функция НайтиЗначениеВТаблице(ТЗ, Номенклатура, Серия, ЦенаПрод, НомерСтроки) // отфильтруем по дате поступления ТЗ.ПолучитьСтрокуПоНомеру(НомерСтроки); Если ТЗ.Номенклатура = Номенклатура Тогда Если (ТЗ.СерияНоменклатуры = Серия) и (ТЗ.ЦенаПрод = ЦенаПрод) и ((ТЗ.ДатаПартии - ДатаПоступления) < 0) Тогда Возврат 1; Иначе Возврат НайтиЗначениеВТаблице(ТЗ, Номенклатура, Серия, ЦенаПрод, НомерСтроки+1); КонецЕсли; Иначе Возврат 0; КонецЕсли; КонецФункции |
|||
23
kloptula
19.10.12
✎
00:12
|
(20 Спасибо дружище
|
|||
24
kloptula
19.10.12
✎
00:15
|
(19) А без рекурсии получается громоздкий код, а с рекурсией красота
|
|||
25
HeroShima
19.10.12
✎
00:22
|
(24) не вижу там громоздкости
|
|||
26
kloptula
19.10.12
✎
00:24
|
(25) Где там?
|
|||
27
HeroShima
19.10.12
✎
00:25
|
(26) в умозрительно трансформированном коде
|
|||
28
kloptula
19.10.12
✎
00:28
|
Изобрази, если не сложно
|
|||
29
HeroShima
19.10.12
✎
00:30
|
(28) один малюсенький цикл
|
|||
30
HeroShima
19.10.12
✎
00:31
|
Очень надеюсь что тема - шутка.
|
|||
31
kloptula
19.10.12
✎
00:31
|
(29) ну....
|
|||
32
HeroShima
19.10.12
✎
00:34
|
(31) поверь на слово
|
|||
33
GANR
19.10.12
✎
00:44
|
(31)(0)Замени-ка ты эту рекурсию на массив (стэк) Как в такой ситуации заменить рекурсию на стэк ??? - прерви поиск, где тебе надо и всё пучком. Этот способ гораздо гибче.
|
|||
34
GANR
19.10.12
✎
00:48
|
(0) А в сабже замени это
НайтиЗначениеВТаблице(ТЗ, Номенклатура, Серия, ЦенаПрод, НомерСтроки+1); на это Возврат НайтиЗначениеВТаблице(ТЗ, Номенклатура, Серия, ЦенаПрод, НомерСтроки+1); Неудивительно, что она 0 возвращает |
|||
35
Semen
19.10.12
✎
03:09
|
(19) Тоже не понял, почему бы просто не перебрать в цикле ТЗ до момента позиционирования на записи удовлетворяющей условию
|
|||
36
Stillcat
19.10.12
✎
06:46
|
Да, слов нет.
(24) Вот твой "громоздкий код" Функция НайтиЗначениеВТаблице(ТЗ, Номенклатура, Серия, ЦенаПрод, НомерСтроки) ТЗ.ВыбратьСтроки(); Пока ТЗ.ПолучитьСтроку()=1 Цикл Если (ТЗ.Номенклатура = Номенклатура) и (ТЗ.СерияНоменклатуры = Серия) и (ТЗ.ЦенаПрод = ЦенаПрод) и ((ТЗ.ДатаПартии - ДатаПоступления) < 0) Тогда НомерСтроки=ТЗ.НомерСтроки; //-Если нужно Возврат 1; КонецЕсли; КонецЦикла; Возврат 0; КонецФункции |
|||
37
Stillcat
19.10.12
✎
06:49
|
В рекурсии конечно великая сила,
но в данном случае - из пушки по воробьям. |
|||
38
kloptula
19.10.12
✎
07:43
|
(36) Работает очень медленно по сравнению с моим вариантом. Лобовое решение, но не оптимальное
|
|||
39
Simod
19.10.12
✎
07:55
|
(38) Оно не может работать медленнее, потому как ПолучитьСтроку() работает быстрее, чем ПолучитьСтрокуПоНомеру()
Функции в (0) в принципе нерабочая, т.к. нет проверки на выход из диапазона строк (НомерСтроки > ТЗ.КоличествоСтрок()) Почитайте какие-нибудь книжки по программированию. |
|||
40
VladZ
19.10.12
✎
08:00
|
(0) Я бы использовал в таком случае "ИндексированнуюТаблицу". Условия вида: (ТЗ.СерияНоменклатуры = Серия) и (ТЗ.ЦенаПрод = ЦенаПрод) фильтруется на ура. Условие (ТЗ.ДатаПартии - ДатаПоступления) < 0 обрабатывать перебором по отфильтрованной ТЗ.
|
|||
41
kloptula
19.10.12
✎
08:12
|
(39) А Вы попробуйте сравнить. ПолучитьСтроку() работает с выборкой всей таблицы, и пока доберешься до нужной строки можешь перебрать почти всю таблицу. А найтиЗначение() и потом ПолучитьСтрокуПоНомеру() позиционирует сразу на нужную строку в таблице.
Иногда лучше жевать, чем говорить |
|||
42
dk
19.10.12
✎
08:18
|
если действительно нужна скорость, то индексы в ТЗ спасут
|
|||
43
ADirks
19.10.12
✎
08:20
|
(41) если надо высокую скорость, то можно и посложней методы применить. Например сортировка + дихотомический поиск.
Ну или сразу ИТ. |
|||
44
kloptula
19.10.12
✎
08:24
|
(42) Согласен, но код сложнее будет, т. к. придется сначала таблицу "переколбасить", а по производительности меня вариант с рекурсией вполне устроил.
|
|||
45
ADirks
19.10.12
✎
08:28
|
(44) Код будет сложнее всего 1 раз. Есть же такая штука, "повторное использование кода".
Например: //_____________________________________________________________________________ Функция ЗначениеДляСравнения(Значение, ПоВнутрПредставлению) Если ПоВнутрПредставлению = 1 Тогда Возврат ЗначениеВСтрокуВнутр(Значение); Иначе Если ТипЗначения(Значение) = 12 Тогда Возврат Значение.ПолучитьПозицию(); КонецЕсли; Возврат Строка(Значение); КонецЕсли; КонецФункции //_____________________________________________________________________________ //Возвращает число: // 0 - ЗначениеКлюча = ЗначениеТЗ // 1 - ЗначениеКлюча > ЗначениеТЗ // -1 - ЗначениеКлюча < ЗначениеТЗ Функция СравнитьСКлючом(Ключ, ТЗ, НомерСтроки, ПоВнутрПредставлению = 0) Перем нк, ИмяКолонки, ЗначениеКлюча, ЗначениеТЗ; Для нк = 1 По Ключ.РазмерСписка() Цикл ЗначениеКлюча = Ключ.ПолучитьЗначение(нк, ИмяКолонки); ЗначениеТЗ = ТЗ.ПолучитьЗначение(НомерСтроки, ИмяКолонки); Если ТипЗначения(ЗначениеКлюча) > 3 Тогда ЗначениеКлюча = ЗначениеДляСравнения(ЗначениеКлюча, ПоВнутрПредставлению); ЗначениеТЗ = ЗначениеДляСравнения(ЗначениеТЗ, ПоВнутрПредставлению); КонецЕсли; Если ЗначениеКлюча > ЗначениеТЗ Тогда Возврат 1; ИначеЕсли ЗначениеКлюча < ЗначениеТЗ Тогда Возврат -1; КонецЕсли; КонецЦикла; Возврат 0; КонецФункции //Бинарный поиск по ключу. Возвращается номер первой или последней строки, совпадающей с ключом //Таблица должна быть предварительно отсортирована (для этого предназначен метод СортироватьПоКлючу()) //Параметры: // - ТЗ - таблица значений, в которой нужно найти строку // - Ключ - список значений, по которым производится поиск. Текстовое представление значения д.б. именем колонки ТЗ. // - ПоВнутрПредставлению - если 1, то при сравнении используется внутреннее представление объекта. // Это нужно в тех случаях, когда есть разные объекты с одинаковым представлением (например, // разные контрагенты с одинаковым наименованием). Естественно, сортировать ТЗ также нужно по внутр. // представлениям (см. СортироватьПоКлючу()). // - НачСтрока, КонСтрока - если отличны от 0, то для поиска будет использован только указанный диапазон строк. // В процессе поиска эти значения меняются таким образом, что их можно затем использовать для // ускорения поиска второй границы. Например: // НачСтрока = 0; КонСтрока = 0; // ТЗ_НайтиПоКлючу2(ТЗ, Ключ, НачСтрока, КонСтрока, 0); //Находим первую запись // ТЗ_НайтиПоКлючу2(ТЗ, Ключ, НачСтрока, КонСтрока, 1); //Находим последнюю запись, но уже гораздо быстрее // - НайтиПоследнюю - 0 - будет найдена первая строка, совпадающая с ключом; 1 - последняя Функция ТЗ_НайтиПоКлючу2(ТЗ, Ключ, ПоВнутрПредставлению = 0, НачСтрока=0, КонСтрока=0, ИскатьПоследнюю = 0) Экспорт Перем н1, н, н2, Рез; Если НачСтрока = 0 Тогда н1 = 1; Иначе н1 = НачСтрока; КонецЕсли; Если КонСтрока = 0 Тогда н2 = ТЗ.КоличествоСтрок(); Иначе н2 = КонСтрока; КонецЕсли; Найдено = 0; Пока н1 < н2 Цикл н = Цел((н1+н2) / 2); Если ИскатьПоследнюю = 1 Тогда н = мин(н + 1, н2); КонецЕсли; Рез = СравнитьСКлючом(Ключ, ТЗ, н, ПоВнутрПредставлению); Если Рез = 0 Тогда Если ИскатьПоследнюю = 0 Тогда н2 = н; Иначе н1 = н КонецЕсли; Найдено = 1; ИначеЕсли Рез < 0 Тогда н2 = н - 1; КонСтрока = н2; Иначе н1 = н + 1; НачСтрока = н1; КонецЕсли; КонецЦикла; Если Найдено = 0 Тогда Если СравнитьСКлючом(Ключ, ТЗ, н1, ПоВнутрПредставлению) = 0 Тогда Найдено = 1; КонецЕсли; КонецЕсли; Если Найдено = 1 Тогда ТЗ.ПолучитьСтрокуПоНомеру(н1); Возврат н1; Иначе Возврат 0; КонецЕсли; КонецФункции //_____________________________________________________________________________ Процедура СортироватьПоКлючу(ТЗ, Ключ, ПоВнутрПредставлению = 0) Экспорт Перем нк, ИмяКолонки, СтрокаСортировки, Зпт; СтрокаСортировки = ""; Зпт = ""; Для нк = 1 По Ключ.РазмерСписка() Цикл Ключ.ПолучитьЗначение(нк, ИмяКолонки); СтрокаСортировки = СтрокаСортировки + Зпт + ИмяКолонки; Зпт = ","; КонецЦикла; Если ПоВнутрПредставлению = 1 Тогда СтрокаСортировки = "*" + СтрЗаменить(СтрокаСортировки, ",", ",*"); КонецЕсли; ТЗ.Сортировать(СтрокаСортировки, 1); КонецПроцедуры |
|||
46
GenAcid
19.10.12
✎
08:51
|
(41)
//Вариант 1 Для каждого СтрокаТЗ из ТЗ Цикл ... КонецЦикла; //Вариант 2 Запрос.Текст = "Выбрать ... Где ..." //Вариант 3. Если очень хочется ПолучитьСтрокуПоНомеру() Для инд = 1 по ТЗ.Количество() Цикл ТЗ.ПолучитьСтрокуПоНомеру(инд); ... КонецЦикла; Действительно "Иногда лучше жевать". И не мучай больше бедный стек вызовов, без особой нужды. |
|||
47
Stillcat
19.10.12
✎
08:53
|
(41) Вы не правы, Ваш вариант медленнее!
Это что касается ПолучитьСтроку()и ПолучитьСтрокуПоНомеру() Еще различия могут быть что сравнение по номенклатуре вынесено у Вас в отдельное условие и проверка напр. (ТЗ.ДатаПартии - ДатаПоступления) < 0) для большинства строк вообще не выполняется, Но в моём варианте условия тоже можно легко разделить. |
|||
48
GenAcid
19.10.12
✎
08:56
|
(47) Ах тыж 7ка)
|
|||
49
Stillcat
19.10.12
✎
08:58
|
Кто-нибудь знает, 1С проверяет сложные условия полностью или по сокращенной схеме?
|
|||
50
ADirks
19.10.12
✎
09:06
|
(49) полность.
|
|||
51
0xFFFFFF
19.10.12
✎
09:06
|
(49) 7.7 проверяет условие целиком, 8.х - по сокращенной.
Это один из пунктов, почему меня подташнивает от 7.7 |
|||
52
kloptula
19.10.12
✎
09:08
|
(47) Чего спорить-то? Изначально сделал по Вашему варианту. Меня не устроила скорость работы отчета. Поэтому и начал извращаться.
|
|||
53
kloptula
19.10.12
✎
09:11
|
(46) Такое ощущение, что для большинства присутствующих - рекурсия что-то злое и неправильное. Лучше 100500 строк дополнительного кода написать, чтобы потом никто не разобрался, как оно работает
|
|||
54
kloptula
19.10.12
✎
09:13
|
(46) можно было и запросом изъеб..ться, лучше уж "мучать бедный стек вызовов", чем мучать бедный регистр остатков
|
|||
55
Simod
19.10.12
✎
09:33
|
(41) Поиск с использованием А НайтиЗначение() и ПолучитьСтрокуПоНомеру() может быть быстрее, когда надо проверить несколько строк. Если надо проверить несколько десятков или сотен строк, то медленнее.
Я так думаю, что там можно было все запросом получить и не изобретать велосипед с квадратными колесами.. |
|||
56
Stillcat
19.10.12
✎
09:33
|
(52) Глупости
|
|||
57
ptiz
19.10.12
✎
09:38
|
Ну и код.
Если к (36) добавить индексы на 3 поля и использовать НайтиСтроки, то будет летать с 1ой космической. |
|||
58
kloptula
19.10.12
✎
09:40
|
(56) см. (55) как раз мой случай, проверка нескольких строк
|
|||
59
kloptula
19.10.12
✎
09:40
|
(55) Там в цикле проверка идет. Запрос в цикле не айс гонять
|
|||
60
Simod
19.10.12
✎
09:45
|
(59) "Там в цикле проверка идет. Запрос в цикле не айс гонять"
Твою ветку уже поместили сюда: OFF: ПятницО Хочешь стать героем дня? |
Форум | Правила | Описание | Объявления | Секции | Поиск | Книга знаний | Вики-миста |