Имя: Пароль:
1C
1C 7.7
v7: Пропуск из ТЗ элементов
,
0 myr4ik07
 
13.09.16
23:09
ТЗ - таблица знач в которой выгружены остатки с фильтром склад и номенкл группа.
Перебираю ТЗ и вижу, что некоторые строки из ТЗ пропускаются в цикле, отладчиком смотрю на "них" - данные есть, обычные строки.
http://paste1c.ru/zJW код

логика заключается удалить из ТЗ строки, которые не соответствуют некому условию, может тут беда?
1 Franchiser
 
гуру
13.09.16
23:15
Да, строки надо перебирать с конца.
Как-то так:
для сч = -ТЗ.Количество() по -1 цикл
сч = сч+1;
КонецЦикла;
2 Franchiser
 
гуру
13.09.16
23:17
ВНИМАНИЕ
Часто требуется удалить строки, удовлетворяющие определенному условию.
Так как при удалении строки из таблицы значений следующая строка становится текущей,
то указанная ниже программа может удалить НЕ ВСЕ необходимые строки.

//ЭТА ПРОГРАММА НЕПРАВИЛЬНАЯ !!!
ТабЗнач.ВыбратьСтроки();
Пока ТабЗнач.ПолучитьСтроку()=1 Цикл
...Если <условие> Тогда
......ТабЗнач.УдалитьСтроку(); //следующая строка стала текущей,
...КонецЕсли;
КонецЦикла;


В этом случае я рекомендую использовать следующий прием:

ТабЗнач.ВыбратьСтроки();
Пока ТабЗнач.ПолучитьСтроку()=1 Цикл
~начало:
...Если <условие> Тогда
......ТабЗнач.УдалитьСтроку(); //следующая строка стала текущей
......Если ТабЗнач.НомерСтроки<>0 Тогда
........ Перейти ~начало;
......КонецЕсли;
...КонецЕсли;
КонецЦикла;

А вот еще один правильный алгоритм, предложенный Wlad:

ТабЗнач.выбратьстроки();
Пока ТабЗнач.ПолучитьСтроку()=1 Цикл
.......Пока (<условие>) и (ТабЗнач.НомерСтроки<>0) Цикл
..............ТабЗнач.УдалитьСтроку(); //следующая строка стала текущей
.......КонецЦикла;
КонецЦикла;
http://www.mista.ru/tutor_1c/tz.htm
3 myr4ik07
 
13.09.16
23:20
(2) да, читал эту статью и по чему то без внимания
4 myr4ik07
 
13.09.16
23:22
(2) атасец, как бы оно

    Пока ТЗ.ПолучитьСтроку() = 1 Цикл    
                ~начало:
                //получим из ТЗ следующую номенклатуру    
                
                //выберем документы с опеределенным периодом
                РасходнаяНакладная = создатьобъект("документ.РасходнаяНакладная");    
                ВыборкаДокументов = РасходнаяНакладная.ВыбратьДокументы(ДнейНеликвид,ТекущаяДата());            

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

очень спасибо
5 Garykom
 
гуру
13.09.16
23:22
Для особо продвинутых удалялщиков... Повторю не нужно удалять строки из ТЗ.

Лучше переносить только нужные строки в новую ТЗ.
6 Franchiser
 
гуру
13.09.16
23:22
я предпочитаю искать в типовом коде 7.7 (например ЗИК) строку по конфигурации"по -1 цикл" и делаю такое удаление по номеру строки.
7 myr4ik07
 
13.09.16
23:25
(5) та мне в голове из 8-ки так привычнее )) вот поэтому и беда
8 hhhh
 
13.09.16
23:28
(7) в 8-ке та же фигня.
9 Franchiser
 
гуру
13.09.16
23:29
(8) в 8-ке если удалять в цикле "для каждого" если не ошибаюсь все ок
10 myr4ik07
 
13.09.16
23:31
(8) для каждого все норм, та и вообще, никаких проблем не было с удаление в 8-ке, не знаю даже о чем ты
11 Franchiser
 
гуру
13.09.16
23:32
(10) не ну если удалять в цикле для сч=0 по Тз.КоличествоСтрок()  то м.б. проблемы
12 myr4ik07
 
13.09.16
23:32
(8) * о чем Вы (10) имел ввиду
13 myr4ik07
 
13.09.16
23:33
(11) ну, короче я не сталкивался с проблемой такой поэтому заблудился )
14 myr4ik07
 
13.09.16
23:33
всем спасибо
15 Zhuravlik
 
13.09.16
23:41
(9) не ок
(0) Лучше всего не морочиться - если условие сложное, перебрать ТЗ, строки к удалению поместить в массив. Потом перебрать массив, из тз удалить нужные строки. Это не самое быстрое, но самое простое. И самое понятное. Особенно когда смотришь на этот код через пару месяцев.
А самое верное решение - это (5) - не допускать наличия в ТЗ лишних строк.
16 Zhuravlik
 
13.09.16
23:44
(2)(3) это для 7.7 :)
(4) Метки использовать нехорошо
17 Franchiser
 
гуру
13.09.16
23:48
(15) есть метод НАйтиСтроки() и потом перебор массива этих строк (с типом строка тз) для последующего удаления
18 Zhuravlik
 
13.09.16
23:50
(17) Тогда уж Скопировать() с отбором по структуре :)
19 Zhuravlik
 
13.09.16
23:51
(17) перебор массива нужен для сложного условия, которое в структуру не загонишь. Но можно добавлять булевскую колонку, заполнять ее по условию, потом Скопировать() с отбором по ней же. По идее самый быстрый способ для v8.
20 Zhuravlik
 
13.09.16
23:54
А для 77 самый лучший способ - это вот такой:

//******************************************************************************
// ОчисткаТЗ()
// Параметры: ТЗ, которую надо очистить
// В ТЗ д.б. Колонки с идентификаторами "НадоУдалить" и "ОПС" (оригинальный порядок строк)
// Описание: очищает ТЗ от ненужных строк
Процедура глОчисткаТЗ(ТЗдляЧистки, ОПС="+ОПС", КолонкаУдалить="НадоУдалить", Режим=0) Экспорт

Попытка НадоУдалить = ТЗдляЧистки.Итог(КолонкаУдалить);
Исключение    Возврат;
КонецПопытки;

ТЗКС = ТЗдляЧистки.КоличествоСтрок();
Если Режим <> 0 Тогда
Сообщить("> ["+ТекущееВремя()+"]: *** удаляем "+НадоУдалить+" из "+ТЗКС+" ****");
КонецЕсли;

Если НадоУдалить <= 0 Тогда Возврат; КонецЕсли;

Если НадоУдалить >= ТЗКС Тогда
ТЗдляЧистки.УдалитьСтроки();
Иначе
ТЗРаб = СоздатьОбъект("ТаблицаЗначений");
ТЗдляЧистки.Выгрузить(ТЗРаб);
ТЗРаб.Сортировать("+"+КолонкаУдалить);
ТЗРаб.Выгрузить(ТЗдляЧистки,1,ТЗКС-НадоУдалить);
ТЗРаб = 0;
КонецЕсли;
Если ОПС = "###" Тогда Возврат; КонецЕсли; //сортировать не надо
//восстановим оригинальный порядок строк
ТЗдляЧистки.Сортировать(ОПС);
КонецПроцедуры    //глОчисткаТЗ()


Взято отсюда http://catalog.mista.ru/public/57376/, пост 19.
В свое время забирал себе в конфу, в глобальник.
21 Franchiser
 
гуру
14.09.16
00:00
Ну Скопировать() я бы не советовал (только в крайнем случае, когда нельзя описать ОТБОР), т.к. если ТЗ большая это и много строк нужно удалять - будет жрать оперативную память.
22 Franchiser
 
гуру
14.09.16
00:01
(20) слишком заморочено, нормальной способ перебор строк ТЗ и удаления с конца - мало кода и все понятно
23 Злопчинский
 
14.09.16
00:51
(22)  этот код практически самый быстрый из нескольких вариантов - ещё на проклабе тестили, и этот ещё можно ускорить заменив метод выгрузить на метод заполнить

А вот вариант с обрезкой количества строк одноимённым методом был чем-то косячный
24 Simod
 
14.09.16
07:43
(0) За последние 15 лет тему поднимали несколько сотен раз.
(23) После сортировки и установки количества строк сбивается сортировка и удаляются не те строки.
25 Злопчинский
 
14.09.16
08:27
(24)  аиесли отсортировать и перекинуть в другую из и обрезать количеством строк то тожеикосяк будет?
26 Это_mike
 
14.09.16
08:31
а индексированную таблицу - рассматриваем? :-)
27 Duke1C
 
14.09.16
09:43
(4) еще какой атасец, глядя на код))
Вот так попробуй:

        СписЗн=СоздатьОбъект("СписокЗначений");
    ТЗ.Выгрузить(СписЗн,,,"Номенклатура");
    ВыбКонПериода=ТекущаяДата();
    Запрос = СоздатьОбъект("Запрос");
    ТекстЗапроса = "Период с ДнейНеликвид по ВыбКонПериода;
    |Номенклатура = Документ.РасходнаяНакладная.Номенклатура;
    |Функция Счётчик = Счётчик();
    |Группировка Номенклатура;
    |Условие(Номенклатура в СписЗн);";
    Если Запрос.Выполнить(ТекстЗапроса) = 0 Тогда
        Возврат;
    КонецЕсли;
    Пока Запрос.Группировка() = 1 Цикл
        Стр=ПолучитьПустоеЗначение("Число");
        Если ТЗ.НайтиЗначение(Запрос.Номенклатура,Стр,"Номенклатура")=1 Тогда
            ТЗ.УдалитьСтроку(Стр);
        КонецЕсли;
    КонецЦикла;
28 Simod
 
14.09.16
13:04
(25) Там как раз и надо отсортировать и выгрузить в другую ТЗ. Тогда Ок. Если отсортировать и обрезать (КоличествоСтрок()), то данные побьются.
29 Злопчинский
 
14.09.16
13:14
(28) это понятно. мну чисто исследовательски интересно если отсортировать и полностью выгрузить(заполнить?) в другую ТЗ - и уже её обрезать по количествустрок - тоже трабл будет..?
30 Эльниньо
 
15.09.16
10:03
Думал, что знаю все алгоритмы удаления "лишних" строк.
Копаюсь в конфе. Нашёл ещё 2 алгоритма
31 Эльниньо
 
15.09.16
10:23
Дарю безвозмездно, т.е даром:

// Алгоритм Эльниньо в один проход и без лишних сущностей и телодвижений
ТЗ.ВыбратьСтроки();
Пока ТЗ.ПолучитьСтроку() = 1 Цикл
    Пока ТЗ.ЧтоТо = Ненужное Цикл
         ТЗ.УдалитьСтроку();
         Если ТЗ.НомерСтроки = 0 Тогда
            Прервать;
         КонецЕсли;
    КонецЦикла;
КонецЦикла;
32 Харлампий Дымба
 
15.09.16
11:08
Инд=Тз.КоличествоСтрок()
Пока Инд>0 Цикл
ТЗ.ПолучитьСтрокуПоНомеру(Инд);
Если ТЗ.ННеНужна=Да Тогда
  ТЗ.УдалитьСтроку(Инд);
КонецЕсли;
Инд=Инд-1;
КонецЦикла;
33 Харлампий Дымба
 
15.09.16
11:16
//Код из типовой (почти):

Функция глТаблицаЗначенийУдалитьСтроки(Таб, ИдКолонки, ЗначениеПоиска) Экспорт
    
    НайденныеСтроки = СоздатьОбъект("ТаблицаЗначений");
    ВремТаб = СоздатьОбъект("ТаблицаЗначений");
    Таб.Выгрузить(НайденныеСтроки);
    НайденныеСтроки.УдалитьСтроки();
    НайденныеСтроки.Выгрузить(ВремТаб);
    
    Для Сч=1 По Таб.КоличествоСтрок() Цикл
        Если ЗначениеПоиска <> Таб.ПолучитьЗначение(Сч,ИдКолонки) Тогда
            Таб.Выгрузить(ВремТаб,Сч,Сч,);
            БылоСтрок = НайденныеСтроки.КоличествоСтрок();
            НайденныеСтроки.КоличествоСтрок(БылоСтрок+1);
            НайденныеСтроки.Заполнить(ВремТаб,БылоСтрок+1);
        КонецЕсли;    
    КонецЦикла;    
    
    Возврат НайденныеСтроки;
    
КонецФункции
34 Злопчинский
 
15.09.16
11:25
(31) кривой код по идее - те же самые траблы с пропусками строк
35 Злопчинский
 
15.09.16
11:26
(33) Таб.ПолучитьЗначение(Сч,ИдКолонки)
- тормозная строка сильно
36 Харлампий Дымба
 
15.09.16
11:36
(35) А кто говорил, что это самый оптимальный код? На мой взгляд, слишком вычурный.
Просто как вариант.
Ну и Таб.ПолучитьЗначение(Сч,ИдКолонки) нужно для универсальности, когда имя колонки отбора заранее неизвестно. Когда известно - можно и через Таб.ВыбратьСтроки()
37 Харлампий Дымба
 
15.09.16
11:48
ТЗ.НоваяКолонка("НадоОставить","Число",1,0);
ТЗ.ВыбратьСтроки();
Пока ТЗ.ПолучитьСтроку()=1 Цикл
    ТЗ.НадоОставить=?(ТЗ.Ненужна=Да,1,0);
КонецЦикла;
ТЗ.Сортировать("НадоОставить-");
ТЗ.КоличествоСтрок(ТЗ.Итог("НадоОставить"));

//либо, вместо последней строчки:
//ИтоговаяТЗ=СоздатьОбъект("ТаблицаЗначений");
//ТЗ.Выгрузить(ИтоговаяТЗ,,,ТЗ.Итог("НадоОставить"));
38 Эльниньо
 
15.09.16
11:55
(34) Ещё один критик. Сколько уже было, потом извинялись.
Посмотри вынимательно.
Покойный залекс тоже поначалу Ха-ха, на следующий день принёс извинения
39 Харлампий Дымба
 
15.09.16
12:02
(37) Извиняюсь, наоборот же -
ТЗ.НадоОставить=?(ТЗ.Ненужна=Да,0,1)
40 Злопчинский
 
15.09.16
15:40
(38) не вопрос, если я облажался - я всегда признаю и извиняюсь.
41 Злопчинский
 
15.09.16
16:02
(38) ага, хитро! ;-)
приношу извинения.
но выморочено.
42 Злопчинский
 
15.09.16
16:02
(37) ТЗ.Сортировать("НадоОставить-");
ТЗ.КоличествоСтрок(ТЗ.Итог("НадоОставить"));

см. (28)
43 Эльниньо
 
15.09.16
16:35
(41) Просто нестандартно, что и приводит к неверной оценке
Почти у всех первая реакция такая.
Слышал, что этот алгоритм уже в каком-то учебнике прописали
44 Злопчинский
 
15.09.16
18:06
(43) я-то вообщем не утверждал на 100% , я оговорочкеу оставил.. "по идее"... бо на первый взгляд оно да... а оно вон как...