|   |   | 
| 
 | 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: ПятницО Хочешь стать героем дня? | 
| Форум | Правила | Описание | Объявления | Секции | Поиск | Книга знаний | Вики-миста |