Имя: Пароль:
1C
1С v8
Проверить заполнение ячеек таблицы значений без перебора
0 Dmitriy_
Kolesnikov
 
17.04.17
18:04
Подскажите, как красиво решить задачу.
Есть ТЗ с большим количеством колонок (они формируются динамически, количество всегда разное)
Мне надо узнать для каждой строки: заполнена ли хотя бы одна ячейка этой строки, начиная с пятой (например) колонки.
Как это сделать красиво, не перебирая в цикле все колонки\ячейки подряд?
Все значения типа число.
1 Любопытная
 
17.04.17
18:10
А как формируются колонки?
В процессе формирования считать сумму всех ячеек по строке и отсеивать те, где сумма = 0.
2 Dmitriy_
Kolesnikov
 
17.04.17
18:15
(1) сначала формируется таблица и выводится в табличное поле формы.
Потом юзер её заполняет числами.
И только потом я должен проанализировать, что он там навводил.

Как посчитать сумму всех ячеек по строке, начиная с пятой, не перебирая циклом все ячейки?
3 Любопытная
 
17.04.17
18:16
(2) забирай ее в запрос и в запросе выкидывай строки, в которых везде нули
4 Любопытная
 
17.04.17
18:17
Только колонки должны быть типизированы для запроса
5 youalex
 
17.04.17
18:18
Можно использовать Вычислить(), но не уверен, что будет быстрее.
6 mistеr
 
17.04.17
18:26
(0) Что за аллергия на циклы? Что-то весеннее?
7 Dmitriy_
Kolesnikov
 
17.04.17
18:30
(6) некрасиво и громоздко. Почему я могу посчитать итог колонки одной строкой без цикла, но не могу посчитать итог строки?
8 Dmitriy_
Kolesnikov
 
17.04.17
18:35
(3) как мне определить в запросе, что в таблице нули во всех колонках?
9 Dmitriy_
Kolesnikov
 
17.04.17
18:41
v8: Как перебрать все значение колонок в таблице значений
Но тут тоже вложенный цикл, громоздко и некрасиво.
10 Buster007
 
17.04.17
18:43
А не громоздко это как?
11 mistеr
 
17.04.17
18:43
(7) >посчитать итог колонки одной строкой без цикла

"Наивный чукотский юноша" (с)
12 Buster007
 
17.04.17
18:44
+(10) 7 строк кода это громоздко?
13 mistеr
 
17.04.17
18:44
(7) Ну напиши функцию, чтоб было красиво.
14 undertaker
 
17.04.17
18:44
(2) сделать массив по количеству строк, по умолчанию там нули, в элемент массива по номеру строки при изменении в ячейке если не 0, то писать 1, потом анализировать массив
15 lodger
 
17.04.17
18:45
ха. ну подумай логически, тебе нужно от платформы узнать где что введено в таблице. угадай как она будет искать твои значения? правильно. циклом. только вот платформенные функции с ограниченными циклами во имя универсальности или заточенности под определенную задачу, типа как НайтиСтроки().
так что громозди свой Для Каждого Цикл.
16 Ildarovich
 
17.04.17
22:45
Если числа в таблице - положительные, а строки - пронумерованы (ведь это табличное поле формы), то можно:
1) добавить в конец таблицы строку с нулями - образцовую незаполненную строку;
2) отсортировать ТЗ по колонкам, начиная с пятой, и далее -  по колонке с номером;
3) найти номер Х образцовой строки в отсортированной таблице;
4) признаком заполненности строки будет то, что ее номер в отсортированной таблице будет больше Х.
Все это можно сделать, не используя ни одного цикла.
17 Ildarovich
 
17.04.17
22:58
+(16) Если числа могут быть и отрицательными, то придется добавлять ограничивающие строки и в начало и в конец таблицы. Незаполненные строки тогда окажутся между ограничивающими после соответствующей сортировки.
18 Неверный Параметр И
 
18.04.17
01:05
(2) Не хочешь циклы - пиши флаги в момент ввода. Ввел пользователь что-то в 6ю колонку, значит после 5й что-то есть.
19 Злопчинский
 
18.04.17
01:12
(18) +100
20 skafandr
 
18.04.17
09:25
(18)+500
21 lodger
 
18.04.17
09:45
(16) ни одного объявленного в коде цикла. зато неявных сразу 2 (это еще неизвестно каким образом платформа проводит сортировку по множеству колонок, может там циклы в цикле)
22 Ildarovich
 
18.04.17
09:53
+(16)+(17) Все, наверное, еще гораздо проще. Незаполненные строки легко найти отбором по структуре СтруктураОтбора = Новый Структура("Колонка5, Колонка6, Колонка7, КолонкаИТД", 0, 0, 0, 0)А то, что предлагается делать в (18) в момент ввода значения, можно сделать по указанному отбору методом ЗаполнитьЗначения.

(21) ...это еще неизвестно... ...может там циклы в цикле...

Практика показывает, что платформенная сортировка - быстрая операция. Обгоняет любой цикл.
23 Ildarovich
 
18.04.17
10:11
(21) А вообще вопрос интересный. По поводу сортировки. Его можно переформулировать так: как быстрее найти минимум в колонке большой таблицы значений: через сортировку и выбор значения из первой строки отсортированной таблицы или путем обхода таблицы типа:
Для Каждого Строка Из ТЗ Цикл Х = Мин(Х, Строка.Значение)
КонецЦикла
Кто-нибудь знает ответ?
24 lodger
 
18.04.17
10:12
25 Ildarovich
 
18.04.17
16:23
(24)+(22) В общем, эксперименты "на коллайдере" показали, что сортировка (из-за N Log N) начинает явно проигрывать циклу, начиная с таблиц размером 20 тысяч строк. Это к тому, что для небольших таблиц (а пользователь вряд-ли будет в диалоге работать с очень большой таблицей) прием из (16) вполне рабочий. Другое дело, что (22) еще лучше и проще.

Ну и более общий вывод, который можно сделать после экспериментов, что вопрос эффективности в данном случае не является актуальным: любой метод поиска пустых строк в ТЗ и с циклом и без цикла работает достаточно быстро, чтобы оператор не замечал этого времени и оптимизации не требовалось.
26 Вафель
 
18.04.17
16:27
сортировка тз однако совсем не дешевая операция
27 Dmitriy_
Kolesnikov
 
18.04.17
20:13
(18) "Не хочешь циклы - пиши флаги в момент ввода. Ввел пользователь что-то в 6ю колонку, значит после 5й что-то есть" - уже плавали.
Всё хорошо, пока вы просто изменяете значения ячеек.
Но как только вы начинаете добавлять и удалять строки - Элемент.ТекущаяСтрока начинает приобретать самые разные значения. То строка до удалённой, то после. И когда вы флагу в этой самой текущей строке начинаете что-то присваивать, то это не имеет отношения к реальности.

&НаСервере
Процедура РаспределениеСуммПоСчетамПриИзмененииНаСервере(НомерСтроки)
    Если НомерСтроки <> Неопределено  и НомерСтроки <= (ЭтаФорма.РаспределениеСуммПоСчетам.Количество()-1) тогда
        ЭтаФорма.РаспределениеСуммПоСчетам[НомерСтроки].Изменена = Истина;
    КонецЕсли;
КонецПроцедуры

&НаКлиенте
Процедура РаспределениеСуммПоСчетамПриИзменении(Элемент)
    Если Элемент.ТекущаяСтрока = Неопределено или Элемент.ТекущаяСтрока > (ЭтаФорма.РаспределениеСуммПоСчетам.Количество()-1) тогда
        Возврат;
    КонецЕсли;
    НомерСтроки = Элемент.ТекущаяСтрока;
    Если Элемент.ТекущийЭлемент.Имя <> "РаспределениеСуммПоСчетамИзменена" тогда
        РаспределениеСуммПоСчетамПриИзмененииНаСервере(НомерСтроки);
    КонецЕсли;
КонецПроцедуры
28 Ildarovich
 
19.04.17
13:13
Из (27) непонятно, подошел ответ из (22) или нет?

Там предлагалось сформировать структуру: ОтборНезаполненных = Новый Структура("Колонка5, Колонка6, Колонка7, ...", 0, 0, 0, ...)и находить незаполненные строки методом НезаполненныеСтроки = ТЗ.НайтиСтроки(ОтборНезаполненных)Структуру можно заполнить один раз при формировании колонок формы и хранить как переменную формы. Кажется, что это как раз то, что нужно. Или нет?
29 Dmitriy_
Kolesnikov
 
19.04.17
18:21
(28) не подошел, потому что на самом деле:
1. Надо находить строки не только с нулевым значением, но и с -1. То есть либо 0, либо -1.
2. Количество колонок очень большое (около 60), и чтобы их засунуть в структуру отбора, всё равно нужен цикл.
3. Параллельно можно\нужно ещё засовывать данные в некую структуру.
В итоге сделал двойной цикл.

    тзПИ = Новый ТаблицаЗначений; // потом добавил 4 колонки

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