Оптимизация цикла

1. ovadia 21.01.20 13:33 Сейчас в теме
Здравствуйте! Сталкивался кто-нибудь с оптимизацией циклов. Нужно сократить время выполнения данного цикла до минут (сейчас на нескольких тысяч строк таблицы работает несколько часов):

for i = 1 to Таблица.Количество() - 1 do
				
				for j = 1 to Таблица.Количество() - i do
					
					if Таблица[j].ВалютаРасчетов = Таблица[j - 1].ВалютаРасчетов
						and Таблица[j].НомерДоговора = Таблица[j - 1].НомерДоговора 
						and Таблица[j].МестоУчета = Таблица[j - 1].МестоУчета 
						and Таблица[j].ДатаОперации = Таблица[j - 1].ДатаОперации then
										
						ВидОперацииТекущий = Строка(Таблица[j].ВидОперации.ПриходРасход);
						ВидОперацииПредыдущий = Строка(Таблица[j - 1].ВидОперации.ПриходРасход);
									
						if  ВидОперацииТекущий = "Приход" and ВидОперацииПредыдущий = "Расход" then
							Таблица.Сдвинуть(j, -1);
						endif;
							
					endif;
		
				enddo;

			enddo;
Показать


Что можно сделать?
По теме из базы знаний
Ответы
В избранное Подписаться на ответы Сортировка: Древо развёрнутое
Свернуть все
15. user623969_dusa 21.01.20 14:11 Сейчас в теме
(1) изменить логику - понять смысл сдвигания строк и сделать по-другому , например как вариант нужно поле сортировки но его нет - добавить к ТЗ колонку - пройтись один раз нужным образом заполнить - отсортировать по колонке
PLAstic; t278; +2 Ответить
18. davealone 165 21.01.20 14:30 Сейчас в теме
(1)
У меня такое чувство, что здесь вся сортировка для того чтобы приходы были раньше расходов в рамках одной аналитики.
А если отсортировать по аналитике сравнения (валюта, договор, место, дата) по возрастанию, и потом по виду операции - это не тоже самое будет?
Или если изначально строки не подряд в рамках аналитики их не нужно сортировать?
21. aezdakov 5 21.01.20 14:44 Сейчас в теме
(1)
ВидОперацииТекущий = Строка(Таблица[j].ВидОперации.ПриходРасход);
ВидОперацииПредыдущий = Строка(Таблица[j - 1].ВидОперации.ПриходРасход);

По логике, тут двойной вызов сервера, для большого количества строк может быть критичным.

(1)
if ВидОперацииТекущий = "Приход" and ВидОперацииПредыдущий = "Расход" then
Таблица.Сдвинуть(j, -1);
endif;

Если условие отработало, то произвели смещение, тогда на следующей итерации всегда будет ВидОперацииПредыдущий = "Приход" и хоть запроверяся всеми условиями. Как по мне внутрь этого условия надо положить наращивание j-того: j = j + 1;
Больше оптимизировать данную логику, мне кажется, не получится. После этих правок узким горлышком будет операция смещения.
Я бы похоронил бы этот алгоритм и создал бы один цикл с перебором с конца, так как суть этого двойного цикла именно в этом. Этим перебором заполнял новую таблицу с теми же колонками, но добавив ещё одну со своим индексом, так как перебор с конца вывернет новую таблицу с зада на перед, а по этому индексу в конце перебора просто бы наложил сортировку.
23. user1274438 21.01.20 14:47 Сейчас в теме
(21)
тут двойной вызов сервера

а таблица у нас, значит, на клиенте.
25. aezdakov 5 21.01.20 14:53 Сейчас в теме
(23)не до конца понял, это вопрос или утверждение?
Почитайте вот это: https://v8.1c.ru/platforma/klient-servernyy-variant-raboty/
Я думал, что тут понятно, что речь идёт про вызов СУБД
27. user1274438 21.01.20 14:56 Сейчас в теме
(25) Вы у автора спросите, где его таблица, и какой у нее тип значения.
30. aezdakov 5 21.01.20 15:04 Сейчас в теме
(27)А зачем мне у автора спрашивать где находится таблица? Тут явно видно обращения через точку: Таблица[j - 1].ВидОперации.ПриходРасход, где ВидОперации - это реквизит таблицы.
Далее - это преобразование этого всего в тип строка, что тоже вызывает СУБД и нет разницы где расположена таблица.
34. user1274438 21.01.20 15:15 Сейчас в теме
(30) ВидОперации - это справочник? документ? может быть, структура? всегда ли там будет обращение к субд?
Но вообще да, скорее всего, там обращение через точку в цикле к объекту ссылочного типа - а это ай-яй-яй
31. Sashares 34 21.01.20 15:05 Сейчас в теме
(21)В объектной модели при получении реквизитов через точку объект кешируется.
Поэтому если там пара видов операций, то как бы именно в этом особой проблемы тут нет.
33. aezdakov 5 21.01.20 15:09 Сейчас в теме
(31)какой объект кэшируется: вся таблица или строка? Лично я не уверен. Без прогона отладчиком однозначно, лично я, сказать не могу.
35. Sashares 34 21.01.20 15:19 Сейчас в теме
(33)Объект, от которого берется реквизит.
ВидОперации.ПриходРасход
очевидно, что ВидОперации, это ссылка, вероятно, на справочник.

Поэтому если в коде от одной ссылки взять 2 реквизита:
МояСсылка.Реквизит1
МояСсылка.Реквизит2
То при первом обращении через точку - для Реквизит1 весь объект прочтется в кэш. И эта операция будет относительно долгой.
И на строке Реквизит2 и другим обращениям к реквизитам будет уже данные из кэша. И эта операция будет уже быстрой.

Поэтому, если нужно получить единоразово 1-2 реквизита у объекта, а весь объект не нужен, то обычно используют функции БСП, которые получают только нужные реквизиты через запросы.
aezdakov; +1 Ответить
36. user1274438 21.01.20 15:26 Сейчас в теме
(35) Вот сейчас специально взял
&НаСервереБезКонтекста
Процедура Команда1НаСервере()
	Для а = 1 по 200 Цикл
		Б = Строка(Справочники.ВидыВычетовНДФЛ.Код103);
		Сообщить(Б);
	КонецЦикла;
КонецПроцедуры

&НаКлиенте
Процедура Команда1(Команда)
	Команда1НаСервере();
КонецПроцедуры
Показать

И посмотрел трассу - 1 запрос к субд
Соответственно, реквизит он посчитал 1 раз. Ну т.е. некоторые вещи сервер 1С умеет кэшировать, когда ему это надо.
и даже потом заменил
Б = Строка(Справочники.ВидыВычетовНДФЛ.Код103.ГруппаВычета);
все равно - 1 запрос.

Тоже самое тут у автора - у него всего 2 варианта - приход и расход, они, с высокой степенью вероятности, также закэшируются 1 раз и до конца обработки живут.

Хотя полностью осуждаю тех, кто обращается через точку. Это ай-яй-яй, и полагаться на сервер 1С в данном случае не хорошо.
aezdakov; +1 Ответить
37. user1274438 21.01.20 15:29 Сейчас в теме
38. aezdakov 5 21.01.20 15:32 Сейчас в теме
(35)Допустим это справочник, то тогда можно предположить, что значение ВидОперации в первой строке может быть не равно значению во второй, и тогда кэширование платформы не даст максимального результата.
Так же, насколько я вас понял, то данная неоднозначность вполне допустима. Как предположил user1274438, что это может быть просто структура, тогда тут вообще может и не быть серверного вызова.
Моё мнение, неоднозначности быть не должно. Ситуации, когда ты не можешь предсказать поведение кода без его отладки меня настораживают.
44. ovadia 21.01.20 19:47 Сейчас в теме
(21)
ВидОперацииТекущий = Строка(Таблица[j].ВидОперации.ПриходРасход);
ВидОперацииПредыдущий = Строка(Таблица[j - 1].ВидОперации.ПриходРасход);

По логике, тут двойной вызов сервера, для большого количества строк может быть критичным.



Избавился от этого. На этапе создания Таблицы (= таблица значений) добавил новый столбец ПриходРасход. В цикле обращаюсь к столбцу непосредственно.

То есть код стал такой:

for i = 1 to Таблица.Количество() - 1 do
                
                for j = 1 to Таблица.Количество() - i do
                    
                    if Таблица[j].ВалютаРасчетов = Таблица[j - 1].ВалютаРасчетов
                        and Таблица[j].НомерДоговора = Таблица[j - 1].НомерДоговора 
                        and Таблица[j].МестоУчета = Таблица[j - 1].МестоУчета 
                        and Таблица[j].ДатаОперации = Таблица[j - 1].ДатаОперации then
                                    
                        if  Таблица[j].ПриходРасход = "Приход" and Таблица[j - 1].ПриходРасход = "Расход" then
                            Таблица.Сдвинуть(j, -1);
                        endif;
                            
                    endif;
        
                enddo;

            enddo;
Показать


В итоге, время формирования отчета уменьшилось до 2 час 18 минут (против более 4 часов).

Буду думать как сделать еще лучше.

Спасибо всем за участие и полезные советы!
45. Sashares 34 21.01.20 19:56 Сейчас в теме
(44)
Буду думать как сделать еще лучше.

Сохраните таблицу после сортировки вашей процедурой в табличный документ.
Выполните сортировку таблицы стандартным методом таблицы значений, как предложено выше и сохраните во второй табличный документ.
Далее можно сравнить табличные документы в сравнением файлов.
Отличаются ли результаты?
Если отличаются, то это отличие влияет на что-нибудь?
46. ovadia 21.01.20 20:00 Сейчас в теме
(45) Не очень понял, что нужно сделать? Зачем сохранять в табличный документ и выполнять сортировку? О какой сортировке речь?
49. Sashares 34 21.01.20 21:01 Сейчас в теме
(46) Ваш цикл меняет строки местами, то есть сортирует.
Нужно сравнить 2 варианта реализации.
1 - ваш.
2 - вариант из (32) только в полях сортировки указать все поля, по которым сравниваются в вашем цикле.
Сравнить можно, например, сохранив таблицы в табличных документах в режиме Отладки, из Табло.
47. starjevschik 21.01.20 20:12 Сейчас в теме
50. t278 56 22.01.20 02:43 Сейчас в теме
(44)
Таблица.Количество()
один раз посчитайте за приделами цикла.

if  Таблица[j].ПриходРасход = "Приход" and Таблица[j - 1].ПриходРасход = "Расход" then
может в переменной использовать логический тип ?

И замером производительности глянуть сколько тратиться на каждую строку.
52. ovadia 22.01.20 10:16 Сейчас в теме
(50) Идею понял. Спасибо. Попробую.
56. t278 56 22.01.20 10:42 Сейчас в теме
(52)скрин замера производительности добавишь?
53. herfis 498 22.01.20 10:29 Сейчас в теме
(44) Смотри. Очевидно, что исходная таблица уже отсортирована по Валюта/Место/Номер/Дата. Иначе бы не получалось сравнивать по имеющемуся условию соседние строки. Что выполняет этот код? Он сортирует по Приход/Расход в рамках комбинации группировок Валюта/Место/Номер/Дата, оставляя остальной порядок строк нетронутым (вероятно, есть дополнительные сортировки по каким-то полям. Может, по времени операции и еще чему-то). По-сути, строки с "приходом" просто "всплывают" наверх в рамках комбинаций группировок Валюта/Место/Номер/Дата.
Самый эффективный способ оптимизировать - это использовать стандартное Сортировать(). Но для этого нужно понять, какие еще поля кроме Валюта/Место/Номер/Дата/ВидОперации нужно включить в выражение сортировки. Возможно, нужно добавить какие-то доп-поля, если их сейчас нет.
Скорее всего, необходима сортировка по Валюта/Место/Номер/Дата/ВидОперации/ВремяОперации или типа того.
Это будет самый эффективный по производительности вариант (эффективнее только сортировать еще в СУБД)
karpik666; +1 Ответить
54. aezdakov 5 22.01.20 10:31 Сейчас в теме
(44) Хороший результат.
Давайте ещё попробуем избавиться от двойного цикла и просто перебрать с конца:
                j = Таблица.Количество() - 1; 
                While j <> 0 do
                   
                    if Таблица[j].ВалютаРасчетов = Таблица[j - 1].ВалютаРасчетов
                        and Таблица[j].НомерДоговора = Таблица[j - 1].НомерДоговора 
                        and Таблица[j].МестоУчета = Таблица[j - 1].МестоУчета 
                        and Таблица[j].ДатаОперации = Таблица[j - 1].ДатаОперации then
                                    
                        if  Таблица[j].ПриходРасход = "Приход" and Таблица[j - 1].ПриходРасход = "Расход" then
                            Таблица.Сдвинуть(j, -1);
                        endif;
                            
                    endif;
                    j = j - 1; 
                enddo;
Показать

По формулам арифметической прогрессии в вашем алгоритме на 1000 строк получится почти 500 тысяч вызовов сравнения ваших 4-х реквизитов в верхнем условии, а операция сравнения тоже может отжимать хорошее время. Если перебирать таблицу с конца, то двойного цикла не нужно, и на 1000 строк у вас будет 1000 вызовов. На теории должно дать значительный прирост, но с практикой может разойтись. Если результат будет слабый, то тогда сортировка или пересоздание таблицы, так как будет ясно, что единственный затык в сдвиге.
По коду, это изуверство, мне тоже в своё время в наследство досталось такое чудо, половина на русском, половина на латинице с использованием переменных с именами как у вас. Рефакторить это всё было тихим ужасом, приходилось выписывать имена переменных и составлять из них словарь. Например, tbTvr (таблица товаров в документе), tbTost (таблица остатков товаров на складе) и так далее, кайф.
55. herfis 498 22.01.20 10:39 Сейчас в теме
(54) Просто перебор с конца не даст правильный результат, я тоже начал думать в эту сторону, но плюнул т.к. чтобы получить правильный результат придется еще костылей натыкать.
Смотри, если есть такая последовательность:
Приход
Расход
Приход
Приход
то последний приход "всплывать" не будет. А должен.
59. aezdakov 5 22.01.20 10:50 Сейчас в теме
(55)Согласен, если таблица именно такая, то это печально и верно работать от обратного не будет. Так же простая сортировка тоже, увы, не решение. Пересоздание таблицы превращается тоже в костылестроение, красивое решение не приходит на ум. Интересная задачка.
63. herfis 498 22.01.20 10:56 Сейчас в теме
(59) Почему это простая сортировка не решение? Что мешает ввести необходимые доп-ключи для получения нужного результата библиотечной сортировкой?
64. Sashares 34 22.01.20 11:08 Сейчас в теме
(63)ТС боится менять алгоритм, так понимаю, чтоб не сломать, т.к. не понимает что он делает и зачем. Поэтому из всех советов воспринимает только те, что не затрагивают сам алгоритм.
user774630; succub1_5; +2 Ответить
67. herfis 498 22.01.20 11:16 Сейчас в теме
(64) Это понятно. И тут ему тоже сложно помочь, так как ТС до сих пор не удосужился сделать замер производительности, чтобы определиться с направлением оптимизации.
Возможно, достаточно будет оптимизировать кэширование "черезточечных" значений. Подозреваю, что сейчас это сделано "в лоб".
Возможно, узким местом является операция сдвига строки в ТЗ. Тут тоже есть идеи.
Возможно, явных узких мест нет и дело в количестве итераций и перестановок - тут тоже есть простор для оптимизации.
66. aezdakov 5 22.01.20 11:13 Сейчас в теме
(63)А разве это уже простая сортировка? Я имел ввиду,то что предложили в (32):
Таблица.Сортировать("ВалютаРасчетов, НомерДоговора, ДатаОперации, ВидОперации");

В чём смысл был в изобретении этого чуда не известно, но он явно должен быть. Таблица имеет некий порядок и раз сравнение только по этим колонкам, а сдвиг только по одной, то порядок, который есть до начала циклов в таблице важен для конечного результата.
К тому же:
(58)
Вполне может оказаться, что достаточную оптимизацию можно получить и не изобретая очередную вариацию алгоритмов сортировки.

Я согласен с этим умозаключением.
68. herfis 498 22.01.20 11:19 Сейчас в теме
(66)
порядок, который есть до начала циклов в таблице важен для конечного результата.

Так я и предлагаю осознать смысл этого доп-порядка и сохранить это доп-упорядочивание введением дополнительных ключей сортировки (за один проход) если сейчас их нет. Могу предположить, что для получения этих доп-ключей необходимо обращение к БД и автору показалось проще просто попытаться сохранить оригинальное упорядочивание.
69. Sashares 34 22.01.20 11:26 Сейчас в теме
(63)Угу, добавить колонку с порядковым номером и заполнить по условию.
Например, так:

Таблица.Колонки.Добавить("НПП");
Таблица.Колонки.Добавить("ПорядокИсходный ");
НПП = 1;
ПорядокИсходный = 1;
Для Инд = 0 По Таблица.Количество()-1 Цикл
	ТекСтр = Таблица[Инд];
	Если Инд > 0 Тогда
		
		ПредСтр = Таблица[Инд-1];
		Если ПредСтр.ВалютаРасчетов <> ТекСтр.ВалютаРасчетов
			ИЛИ ПредСтр.НомерДоговора <> ТекСтр.НомерДоговора
			ИЛИ ПредСтр.МестоУчета <> ТекСтр.МестоУчета
			ИЛИ ПредСтр.ДатаОперации <> ТекСтр.ДатаОперации Тогда
			НПП = НПП + 1;
		КонецЕсли;
		
	КонецЕсли;
	
	ТекСтр.НПП = НПП;
	ТекСтр.ПорядокИсходный  = ПорядокИсходный;
        ПорядокИсходный  = ПорядокИсходный + 1;
КонецЦикла;

Таблица.Сортировать("НПП,ПриходРасход,ПорядокИсходный");
Таблица.Колонки.Удалить("НПП");
Таблица.Колонки.Удалить("ПорядокИсходный ");
Показать
65. karpik666 3760 22.01.20 11:11 Сейчас в теме
(59) что в ней интересного? простая сортировка, только сделана "контуженным" выходцем из других языков.
70. aezdakov 5 22.01.20 11:27 Сейчас в теме
(65)Даже не знаю какой тут пример сообразить. Вот приезжают туристы в Москву, шарются по метро и глазеют на потолки, трут бронзовые постаменты, а ты об них спотыкаешься со словами: что тут интересного, это же просто метро, общественный транспорт. Глубинный смысл моего интереса объяснять не имею желания.
71. karpik666 3760 22.01.20 11:34 Сейчас в теме
(70) если вы хотите искать глубинный смысл там, где его нет, то вам сюда https://www.govnokod.ru/1c , многие философы сошли с ума в понимании замыслов творений этих авторов. В принципе решение из (32) верное, однако я бы поменял на Таблица.Сортировать("ВалютаРасчетов, НомерДоговора, МестоУчета, ДатаОперации, Приоритет");
где Приоритет определяется по виду операции.
либо тоже самое предложено в (53).
72. aezdakov 5 22.01.20 13:12 Сейчас в теме
(71)Хорошо, давайте развивать мысль:
Сортировать (Sort)
Синтаксис:

Сортировать(<Колонки>, <ОбъектСравнения>)
Параметры:

<Колонки> (обязательный)

Тип: Строка.
Список имен колонок, разделенных запятыми, по которым производится сортировка таблицы. После каждого имени колонки через пробел может быть указано направление сортировки. Направление определяется: "Убыв" ("Desc") - упорядочивать по убыванию; "Возр" ("Asc") - упорядочивать по возрастанию. По умолчанию сортировка производится по возрастанию. Порядок указания имен колонок таблицы определяет порядок сортировки. Это означает, что сначала таблица сортируется по колонке, указанной первой. Затем группы строк с одинаковым значением в этой колонке сортируются по колонке, которая указана второй, и так далее.

Получается, что сортировкой по первой колонке мы сразу же ломаем ту сортировку, что первоначально была заложена при построении таблицы. Может получиться ситуация, когда строка, которая не должна была по первоначальному алгоритму сместиться, поменяет свою дислокацию. Нет, можно надеется на то, что здесь нет глубинного смысла, то тогда всё будет работать верно, но настораживают слова ТС, что алгоритм работает правильно, хотя и долго. А раз так, то есть вероятность, что смысл в этом алгоритме есть.
Не знаю, я видимо оптимист, так как считаю, что человек, который писал код, всё же таки думал, а не бил головой об клавиатуру.
Если порядок в результате не важен, то применяем сортировку и дело с концом. ТС же пришёл с просьбой оптимизировать что есть. Мы же вступили в полемику на гране срача и в конечном итоге только и делаем что гадаем на кофейной гуще.
Смысла дальше продолжать я теперь не вижу для себя, так как последнее что я слышу: "тебе больше всех надо? Тут нужна только стандартная сортировка". Я про неё ещё в своём первом комментарии сказал. Приходят, вырывают из контекста, перефразируют. Надоело.
75. karpik666 3760 22.01.20 13:48 Сейчас в теме
(72)
Получается, что сортировкой по первой колонке мы сразу же ломаем ту сортировку, что первоначально была заложена при построении таблицы
, а зачем тогда нужен весь алгоритм, если сортировка не такая как в решении? в примере ясно показано, что строка сдвигается вверх, если предыдущая имеет одинаковые поля. Какой смысл вообще сортировать данную выборку, если она имеет хаотический порядок. Вы хватаетесь только за часть, но не видите всей картины.
Не знаю, я видимо оптимист, так как считаю, что человек, который писал код, всё же таки думал, а не бил головой об клавиатуру.
Так смотрите, уже привели пример кода, когда человек не думает о решении.
Смысла дальше продолжать я теперь не вижу для себя, так как последнее что я слышу: "тебе больше всех надо? Тут нужна только стандартная сортировка". Я про неё ещё в своём первом комментарии сказал. Приходят, вырывают из контекста, перефразируют. Надоело.

Не знал, что своими комментариями, я задел ваши чувства, не расстраивайтесь - все будет хорошо. Желаю вам прекрасного не тормозящего кода;)
57. herfis 498 22.01.20 10:43 Сейчас в теме
(54)
ефакторить это всё было тихим ужасом, приходилось выписывать имена переменных и составлять из них словарь. Например, tbTvr (таблица товаров в документе), tbTost (таблица остатков товаров на складе) и так далее, кайф.

Нафига выписывать? Я когда такое рефакторю, то как только понимаю смысл переменной сразу ее везде меняю через "найти и заменить".
60. Sashares 34 22.01.20 10:50 Сейчас в теме
(57)ПКМ - Рефакторинг - Переименовать
61. herfis 498 22.01.20 10:53 Сейчас в теме
(60) Точно! Никак не привыкну :) Изначально кажись даже пункта "рефакторинг" в конфигураторе не было.
62. aezdakov 5 22.01.20 10:56 Сейчас в теме
(57)
Нафига выписывать?

Я просто боялся это делать в базе, в которой любое движение вызывало лавину из ошибок. Да и этот код лежал на веб-сервисе для мобильного приложения, написанного на JS, логика была в том, что наименования переменных в этом приложении было равно наименованиям в 1С, поэтому понять что это за переменная было проще, но всё же вызывало боль.
58. herfis 498 22.01.20 10:50 Сейчас в теме
(54) Другими словами, в общем случае за "один проход" это не решить. Необходимо тем большее количество итераций, чем "хуже" изначальная сортировка. В каких-то случаях придется "возвращаться" и не один раз.
Но значительно оптимизировать количество итераций и перестановок безусловно можно. Вопрос только, стоит ли? Вполне может оказаться, что достаточную оптимизацию можно получить и не изобретая очередную вариацию алгоритмов сортировки.
40. herfis 498 21.01.20 15:54 Сейчас в теме
(1) Ну, перво-наперво:
size = Таблица.Количество();
for i = -size to -1 do
	j = -i - 1;
	if Таблица[j].ВалютаРасчетов = Таблица[j - 1].ВалютаРасчетов
		and Таблица[j].НомерДоговора = Таблица[j - 1].НомерДоговора 
		and Таблица[j].МестоУчета = Таблица[j - 1].МестоУчета 
		and Таблица[j].ДатаОперации = Таблица[j - 1].ДатаОперации then
		
		ВидОперацииТекущий = Строка(Таблица[j].ВидОперации.ПриходРасход);
		ВидОперацииПредыдущий = Строка(Таблица[j - 1].ВидОперации.ПриходРасход);
		
		if  ВидОперацииТекущий = "Приход" and ВидОперацииПредыдущий = "Расход" then
			Таблица.Сдвинуть(j, -1);
		endif;
	endif;
enddo;
Показать

Ан нет. Так не получится... Сейчас
41. Sashares 34 21.01.20 16:04 Сейчас в теме
(40)Ну уж. Так вы 1 раз таблицу проходите.
73. Indgo 338 22.01.20 13:39 Сейчас в теме
что то вроде того:
таб = таблица.скопировать(); //или выгрузить Перемещаем талицузначений (в оперативную память)
ОписаниеТипа = Новый ОписаниеТипов("Число",
        Новый КвалификаторыЧисла(1, 0));
таб.колонки.добавить("Приход", ОписаниеТипа);
для каждого ном из рез Цикл
	ВидОперацииТекущий = Строка(ном.ВидОперации.ПриходРасход);
	Если ВидОперацииТекущий = "Приход" тогда
		ном.Приход = 1;
	иначе
		ном.Приход = 2;
	КонецЕсли;	
КонецЦикла;	
таб.сортировать("ДатаОперации,ВалютаРасчетов,МестоУчета,НомерДоговора,Приход");
таблица.загрузить(таб);
Показать

Если сортировка не подходит то
1. необходимо поделить таблицу пополам, а вторую фильтровать
2. если работать с 2-умя идентичными талицами будет быстрее так как не будет задержек сдвига в первой таблице.
succub1_5; +1 Ответить
2. Guyer 20 21.01.20 13:36 Сейчас в теме
А Если через НайтиСтроки() ????
4. ovadia 21.01.20 13:40 Сейчас в теме
(2) А что искать? Цикл не ищет, а сдвигает (упорядочивает) строки в определенном порядке.
6. VictorRGB2 13 21.01.20 13:44 Сейчас в теме
(4) а Таблица куда потом передается или что с ней дальше делается?
не рассматривали вариант просто перезаполнить новую таблицу уже отсортированными данными?
поучится быстрее, чем двигать строки
3. coollerinc 185 21.01.20 13:40 Сейчас в теме
Может в запросе сравнить эти таблицы? А потом двигать все в таблицах
5. ovadia 21.01.20 13:43 Сейчас в теме
(3) Таблица же одна. После каждого прохода по i она реструктуризуется при выполнении условия.
7. coollerinc 185 21.01.20 13:44 Сейчас в теме
(5)
Соеденить саму с собой
8. soft_wind 21.01.20 13:44 Сейчас в теме
э-э-э. а просто отсортировать таблицу?
11. ovadia 21.01.20 13:47 Сейчас в теме
(8) Тут нет по-моему однозначного критерия сортировки.
9. Fril 21.01.20 13:45 Сейчас в теме
Это задачка на сообразительность или реально где-то используется?
10. ovadia 21.01.20 13:46 Сейчас в теме
(9) В реальном работающем коде. Только очень медленном на больших данных.
12. soft_wind 21.01.20 13:52 Сейчас в теме
(10)

В реальном работающем коде. Только очень медленном на больших данных.

Это наверно, франчайзи делали!!! Их почерк!!!
succub1_5; +1 Ответить
14. ovadia 21.01.20 14:04 Сейчас в теме
(12)
Это наверно, франчайзи делали!!! Их почерк!!!


)) Код работающий, то есть дает правильный результат. Когда делал, тестировал на нескольких днях максимум и было не так ощутимо. Но столкнулись с месячным отчетом и оказалось слишком медленно формирует результат.
43. TODD22 18 21.01.20 16:21 Сейчас в теме
(12)
Это наверно, франчайзи делали!!! Их почерк!!!

У вас есть шанс утереть им нос и представить достойное решение.
13. ovadia 21.01.20 13:55 Сейчас в теме
Есть конкретная строка таблицы. Нужно взять эту строку и сравнить по условию со всеми строками таблицы. Если условие выполняется, то нужно поменять местами текущую строку и соседнюю. И так сделать для каждой строки таблицы. В итоге строки перемешаются и встанут как нужно.
16. YanTsys 12 21.01.20 14:20 Сейчас в теме
В конфигураторе есть средства отладки позволяющие сделать замер времени какие строки сколько процессорного времени расходуют, уверен что самая тормознутая операция это перемещение строки.
Вы сдвигаете строчки по одной позиции.
Необходимо сделать таблицу соответствия строк реальной таблицы с тем какие номера строк вы в итоге хотели бы получить. Не сдвигать строки а менять их номер в таблице индексов.
После формирования таблицы индексов каждую строку в таблице сдвинуть ровно один раз не по одной строке а сразу туда куда нужно типа
Таблица.Сдвинуть(j, -17);

Но мне больше нравится вариант не с перемещением строк а с заполнением другой ТЗ исходя из имеющейся и с обратным копированием уже готовой ТЗ.
17. succub1_5 88 21.01.20 14:28 Сейчас в теме
По коду кажется что для удобства пользователя строки с одинаковыми реквизитами, но с разными ВидамиОпераций идут друг за другом (?)
Если я правильно понял, тогда так можно сделать
51. succub1_5 88 22.01.20 09:54 Сейчас в теме
(17)
1 шаг - через отбор разделить ТЗ на 2: с Приходом и Расходом, (2-3 сек)
2 шаг - добавить в каждую таблицу по столбцу (пусть "Номер", Число), 1 таблицу "ТЗ_Приход" заполнить "Номер" нечетными числами , 2 таблицу "ТЗ_Расход" заполнить четными числами, (10 сек)
3 шаг - объединить обе таблицы и сортировать по реквизитам по которым сравнение в цикле + по новому "Номер" - тогда все по порядку будет, а Приход/Расход друг за другом.
*это сработает если условно одинаково приходов/расходов, если есть непарные строки, то другой алгоритм, но с 1 циклом.
19. starjevschik 21.01.20 14:34 Сейчас в теме
Надо с алгоритмом подумать.
Я так понял, тут идея в том, чтобы в одинаковых строках сначала шли приходы, а потом расходы.
Я бы, наверное, добавил пару колонок: 1) сделал бы в каждой строке ключ вида "" + Валюта + Место + ... что там входит в ключ и 2) порядок: приход = 1, расход - 2
потом простой сортировкой задача решается без многоразового прохода таблицы (кмк тут даже оценить количество проходов не так-то просто).

ЗЫ ключи, если есть возможность, заполнить на стадии заполнения таблицы, будет еще быстрее.
22. user1274438 21.01.20 14:46 Сейчас в теме
(19) Да можно просто отсортировать по нужным полям, включая приход/расход.
Но автор же сказал, что не знает однозначного способа сортировки. Ну и пусть дальше не знает.
24. starjevschik 21.01.20 14:48 Сейчас в теме
(22) нет, просто сортировать не получится, т.к. нам нужна сортировка по виду операции только в пределах ключа из четырех (или сколько их там) колонок.
Поэтому и не знает, что тут для сортировки нужна еще одна колонка.
Задача вообще не сложная, но способ ее решения внушает. Таланты среди нас )
26. Sashares 34 21.01.20 14:54 Сейчас в теме
(24)
но способ ее решения внушает

Чем внушает?
28. starjevschik 21.01.20 15:01 Сейчас в теме
(26) гениальностью. Автору кода было проще забубенить эти циклы со сдвигом строк, чем банальную сортировку таблицы.
29. Sashares 34 21.01.20 15:03 Сейчас в теме
(28)А, текущая реализация. Да, согласен=)
20. YanTsys 12 21.01.20 14:44 Сейчас в теме
Можно еще добавить вспомогательную колонку в ТЗ в ней заполнить номера позиций в которых в итоге должна оказаться строка, потом применить команду Сортировать и удалить эту вспомогательную колонку
32. Lenten 25 21.01.20 15:08 Сейчас в теме
Таблица.Сортировать("ВалютаРасчетов, НомерДоговора, ДатаОперации, ВидОперации");



ВидОперации поставьте Убыв или Возр. Не знаю что у вас раньше будет. Остальные колонки, я так понял, не имеет значение в каком порядке
42. Sashares 34 21.01.20 16:14 Сейчас в теме
(32)Поддержу.
Сортировать по всем колонкам, по которым сравнение в текущей процедуре.
И только если этот вариант не подходит, имеет смысл заморачиваться.
39. user1274438 21.01.20 15:34 Сейчас в теме
Ну вот так всегда, вместо помощи ТС-у с сортировкой устроили срач по серверным вызовам и обращениям к СУБД! О горе нам!
48. vadim1011985 99 21.01.20 20:37 Сейчас в теме
Я конечно не уверен , но мне кажется что в каждом условии обращение к табличной части через итератор цикла не очень

Может перед условиями сразу получить ссылки на нужные строки табличной части и условие переписать через эти ссылки
74. ovadia 22.01.20 13:47 Сейчас в теме
Сделал код таким:

size_Таблица = Таблица.Количество();
			
for i = 1 to size_Таблица - 1 do				
	for j = 1 to size_Таблица - i do
					
		if Таблица[j].Ключ_ВалютаДоговорМестоУчетаДатаОперации = Таблица[j - 1].Ключ_ВалютаДоговорМестоУчетаДатаОперации then
						
			if  Таблица[j].ПриходРасходБулево and NOT Таблица[j - 1].ПриходРасходБулево then
				Таблица.Сдвинуть(j, -1);
			endif;
						
		endif;
				
	enddo;		
enddo;
Показать


Время выполнения сократилось до 1 часа 05 минут (против 2 час. 18 мин и более 4 часов в начале).

Существенный прирост дала замена блока нескольких условий на одно сравнение!

Пока так и не придумал, как здесь правильно избавиться от вложенного цикла так, чтобы результаты не поломались. Сортировка таблицы уже была. Перед этим блоком у меня как раз и написано:
Таблица.Сортировать("НаименованиеВладельца, ВалютаРасчетов Возр, МестоУчетаДС, ДатаОперации");


Рассматриваемый код выполняет дополнительное упорядочивание ранее отсортированной таблицы, так как сортировка не дает нужного результата (правильного расположения строк таблицы).

В принципе пока что меня результат устраивает. Спасибо!
76. Sashares 34 22.01.20 14:11 Сейчас в теме
(74)Из (69) попробуйте вариант.
77. пользователь 22.01.20 14:20
Сообщение было скрыто модератором.
...
78. Donpager 1 22.01.20 14:57 Сейчас в теме
(74) Так и не могу понять почему не написать вместо
Таблица.Сортировать("НаименованиеВладельца, ВалютаРасчетов Возр, МестоУчетаДС, ДатаОперации");

Так
Таблица.Сортировать("НаименованиеВладельца, ВалютаРасчетов Возр, МестоУчетаДС, ДатаОперации,ПриходРасходБулево Возр/Убыв");


И не нужен будет весь алгоритм
79. acanta 22.01.20 15:02 Сейчас в теме
(74) это связано с тем, что в 8 ке условия тоже интерпретатор?
80. kasper076 101 22.01.20 16:10 Сейчас в теме
ВЫБРАТЬ
	АВТОНОМЕРЗАПИСИ() КАК НомерСтроки,
	ВЫРАЗИТЬ(МояТаблица.ВалютаРасчетов КАК Справочник.Валюты) КАК Валюта,
	ВЫРАЗИТЬ(МояТаблица.ДатаОперации КАК ДАТА) КАК ДатаОперации,
	ВЫРАЗИТЬ(МояТаблица.МестоУчета КАК Справочник.Склады) КАК МестоУчета,
	ВЫРАЗИТЬ(МояТаблица.Договор КАК Справочник.СоглашенияСПоставщиками) КАК Договор,
	ВЫРАЗИТЬ(МояТаблица.ВидДвижения КАК БУЛЕВО) КАК ВидДвижения
ПОМЕСТИТЬ МояТаблица
ИЗ
	&МояТаблица КАК МояТаблица
;

////////////////////////////////////////////////////////////­////////////////////
ВЫБРАТЬ
	МояТаблица.НомерСтроки КАК НомерСтроки,
	"000000000" + МояТаблица.Валюта.Код КАК Аргумент
ПОМЕСТИТЬ ВТ_Транспонированная
ИЗ
	МояТаблица КАК МояТаблица

ОБЪЕДИНИТЬ ВСЕ

ВЫБРАТЬ
	МояТаблица.НомерСтроки,
	"1000" + ПОДСТРОКА("01020304050607080910111213141516171819202122232425262728293­031", ДЕНЬ(МояТаблица.ДатаОперации) * 2 - 1, 2) + ПОДСТРОКА("010203040506070809101112", МЕСЯЦ(МояТаблица.ДатаОперации) * 2 - 1, 2) + ПОДСТРОКА("0123456789", ГОД(ВЫРАЗИТЬ(МояТаблица.ДатаОперации КАК ДАТА)) / 1000 + 1, 1) + ПОДСТРОКА("0123456789", СЕКУНДА(ДОБАВИТЬКДАТЕ(ДАТАВРЕМЯ(1, 1, 1), СЕКУНДА, ГОД(ВЫРАЗИТЬ(МояТаблица.ДатаОперации КАК ДАТА)) * 0.06)) / 6 + 1, 1) + ПОДСТРОКА("0123456789", СЕКУНДА(ДОБАВИТЬКДАТЕ(ДАТАВРЕМЯ(1, 1, 1), СЕКУНДА, ГОД(ВЫРАЗИТЬ(МояТаблица.ДатаОперации КАК ДАТА)) * 0.6)) / 6 + 1, 1) + ПОДСТРОКА("0123456789", СЕКУНДА(ДОБАВИТЬКДАТЕ(ДАТАВРЕМЯ(1, 1, 1), СЕКУНДА, ГОД(ВЫРАЗИТЬ(МояТаблица.ДатаОперации КАК ДАТА)) * 6)) / 6 + 1, 1)
ИЗ
	МояТаблица КАК МояТаблица

ОБЪЕДИНИТЬ ВСЕ

ВЫБРАТЬ
	МояТаблица.НомерСтроки,
	"2" + МояТаблица.МестоУчета.Код
ИЗ
	МояТаблица КАК МояТаблица

ОБЪЕДИНИТЬ ВСЕ

ВЫБРАТЬ
	МояТаблица.НомерСтроки,
	"3" + ПОДСТРОКА("0123456789", СЕКУНДА(ДОБАВИТЬКДАТЕ(ДАТАВРЕМЯ(1, 1, 1), СЕКУНДА, МояТаблица.Договор.Код * 0.000000006)) / 6 + 1, 1) + ПОДСТРОКА("0123456789", СЕКУНДА(ДОБАВИТЬКДАТЕ(ДАТАВРЕМЯ(1, 1, 1), СЕКУНДА, МояТаблица.Договор.Код * 0.00000006)) / 6 + 1, 1) + ПОДСТРОКА("0123456789", СЕКУНДА(ДОБАВИТЬКДАТЕ(ДАТАВРЕМЯ(1, 1, 1), СЕКУНДА, МояТаблица.Договор.Код * 0.0000006)) / 6 + 1, 1) + ПОДСТРОКА("0123456789", СЕКУНДА(ДОБАВИТЬКДАТЕ(ДАТАВРЕМЯ(1, 1, 1), СЕКУНДА, МояТаблица.Договор.Код * 0.000006)) / 6 + 1, 1) + ПОДСТРОКА("0123456789", СЕКУНДА(ДОБАВИТЬКДАТЕ(ДАТАВРЕМЯ(1, 1, 1), СЕКУНДА, МояТаблица.Договор.Код * 0.00006)) / 6 + 1, 1) + ПОДСТРОКА("0123456789", СЕКУНДА(ДОБАВИТЬКДАТЕ(ДАТАВРЕМЯ(1, 1, 1), СЕКУНДА, МояТаблица.Договор.Код * 0.00006)) / 6 + 1, 1) + ПОДСТРОКА("0123456789", СЕКУНДА(ДОБАВИТЬКДАТЕ(ДАТАВРЕМЯ(1, 1, 1), СЕКУНДА, МояТаблица.Договор.Код * 0.0006)) / 6 + 1, 1) + ПОДСТРОКА("0123456789", СЕКУНДА(ДОБАВИТЬКДАТЕ(ДАТАВРЕМЯ(1, 1, 1), СЕКУНДА, МояТаблица.Договор.Код * 0.006)) / 6 + 1, 1) + ПОДСТРОКА("0123456789", СЕКУНДА(ДОБАВИТЬКДАТЕ(ДАТАВРЕМЯ(1, 1, 1), СЕКУНДА, МояТаблица.Договор.Код * 0.06)) / 6 + 1, 1) + ПОДСТРОКА("0123456789", СЕКУНДА(ДОБАВИТЬКДАТЕ(ДАТАВРЕМЯ(1, 1, 1), СЕКУНДА, МояТаблица.Договор.Код * 0.6)) / 6 + 1, 1) + ПОДСТРОКА("0123456789", СЕКУНДА(ДОБАВИТЬКДАТЕ(ДАТАВРЕМЯ(1, 1, 1), СЕКУНДА, МояТаблица.Договор.Код * 6)) / 6 + 1, 1)
ИЗ
	МояТаблица КАК МояТаблица
;

////////////////////////////////////////////////////////////­////////////////////
ВЫБРАТЬ
	1 КАК Позиция,
	1 КАК ЧленРяда
ПОМЕСТИТЬ СтепеннойРяд

ОБЪЕДИНИТЬ

ВЫБРАТЬ
	2,
	31

ОБЪЕДИНИТЬ

ВЫБРАТЬ
	3,
	961

ОБЪЕДИНИТЬ

ВЫБРАТЬ
	4,
	29791

ОБЪЕДИНИТЬ

ВЫБРАТЬ
	5,
	923521

ОБЪЕДИНИТЬ

ВЫБРАТЬ
	6,
	28629151

ОБЪЕДИНИТЬ

ВЫБРАТЬ
	7,
	887503681

ОБЪЕДИНИТЬ

ВЫБРАТЬ
	8,
	1742810335

ОБЪЕДИНИТЬ

ВЫБРАТЬ
	9,
	2487512833

ОБЪЕДИНИТЬ

ВЫБРАТЬ
	10,
	4098453791

ОБЪЕДИНИТЬ

ВЫБРАТЬ
	11,
	2498015937

ОБЪЕДИНИТЬ

ВЫБРАТЬ
	12,
	129082719
;

////////////////////////////////////////////////////////////­////////////////////
ВЫБРАТЬ
	ПОДСТРОКА("0123456789", СтепеннойРяд.Позиция, 1) КАК Символ,
	СтепеннойРяд.Позиция КАК Код
ПОМЕСТИТЬ КодоваяТаблица
ИЗ
	СтепеннойРяд КАК СтепеннойРяд

ИНДЕКСИРОВАТЬ ПО
	Символ
;

////////////////////////////////////////////////////////////­////////////////////
ВЫБРАТЬ
	ИсходныеДанные.НомерСтроки КАК НомерСтроки,
	ПОДСТРОКА(ИсходныеДанные.Аргумент, СтепеннойРяд.Позиция, 1) КАК СимволКода,
	СтепеннойРяд.ЧленРяда КАК ЧленРяда
ПОМЕСТИТЬ ОтдельныеСимволы
ИЗ
	ВТ_Транспонированная КАК ИсходныеДанные,
	СтепеннойРяд КАК СтепеннойРяд
;

////////////////////////////////////////////////////////////­////////////////////
ВЫБРАТЬ
	ОтдельныеСимволы.НомерСтроки КАК НомерСтроки,
	СУММА(ОтдельныеСимволы.ЧленРяда * КодоваяТаблица.Код) КАК Хэш
ПОМЕСТИТЬ ВыходныеДанные
ИЗ
	ОтдельныеСимволы КАК ОтдельныеСимволы
		ВНУТРЕННЕЕ СОЕДИНЕНИЕ КодоваяТаблица КАК КодоваяТаблица
		ПО ОтдельныеСимволы.СимволКода = КодоваяТаблица.Символ

СГРУППИРОВАТЬ ПО
	ОтдельныеСимволы.НомерСтроки
;

////////////////////////////////////////////////////////////­////////////////////
ВЫБРАТЬ
	МояТаблица.НомерСтроки КАК НомерСтроки,
	МояТаблица.Валюта КАК Валюта,
	МояТаблица.ДатаОперации КАК ДатаОперации,
	МояТаблица.МестоУчета КАК МестоУчета,
	МояТаблица.Договор КАК Договор,
	ВыходныеДанные.Хэш КАК Хэш,
	МояТаблица.ВидДвижения КАК ВидДвижения
ИЗ
	МояТаблица КАК МояТаблица
		ЛЕВОЕ СОЕДИНЕНИЕ ВыходныеДанные КАК ВыходныеДанные
		ПО (МояТаблица.НомерСтроки = ВыходныеДанные.НомерСтроки)

УПОРЯДОЧИТЬ ПО
	Хэш,
	ВидДвижения
АВТОУПОРЯДОЧИВАНИЕ
Показать


Использованы статьи Расчет хэш-функции в запросе и Выразить число как строку и дату как строку в запросе
Поскольку в первом запросе используется функция "АВТОНОМЕРЗАПИСИ()", то требуется платформа 8.3.14. Если же номер строки уже есть в таблице, то требования к платформе понижаются.
Коротко об алгоритме: в первом запросе помещаем таблицу значений во временную таблицу. Во втором, каждое значение каждой колонки преобразуется к строке длинной 12 символов ( Для справочников используется код) и помещается в новую строку в колонку "Аргумент". Затем для набора аргументов каждого номера строки рассчитывается хэш.
81. acanta 22.01.20 16:42 Сейчас в теме
А почему именно хэш, а не бухгалтерский остаток? Приход - расход, если отрицательный, тогда строка расхода снижается пока не уйдет в плюс?
Меньше вычислений чем в уме?
82. kasper076 101 22.01.20 17:05 Сейчас в теме
(81) Так нужно же двигать строку все значения колонок которой совпадают со значениями соответствующих колонок соседней строки.
83. PLAstic 295 23.01.20 14:09 Сейчас в теме
Мне кажется, проще было бы загнать таблицу в запрос и запросом упорядочить как надо. Если я правильно понял задачу по комментариям...
Оставьте свое сообщение
Вакансии
Программист 1С
Москва
зарплата от 180 000 руб. до 220 000 руб.
Полный день

Аналитик 1С / Бизнес-аналитик
Нижний Новгород
зарплата от 100 000 руб. до 250 000 руб.
Временный (на проект)

Программист 1С
Москва
зарплата от 250 000 руб.
Полный день

Программист 1C
Волгоград
зарплата от 200 000 руб.
Полный день

Аналитик
Санкт-Петербург
зарплата от 200 000 руб. до 250 000 руб.
Полный день