О цикле обратном замолвите слово...

30.05.23

Разработка - Механизмы платформы 1С

Однажды, написав статью, расписывающую достоинства 1С, я упомянул среди недостатков - мне не хватает "обратного цикла". При этом, столкнулся с непониманием - "а зачем тебе обратный цикл". Сегодня я отвечу на этот вопрос.
 
 Предисловие

Я обожаю 1С. Программировать в данной среде мне очень комфортно, а главное - разработка занимает относительно немного времени. В своё время, я даже написал статью на Хабре, в которой хвалил 1С и высказывал некоторые претензии.
Данной статьёй я планирую начать цикл "придирок" к языку, платформе, типовым решениям 1С, в целом, высказаться на тему - чего ещё не хватает.

Я искренне верю, что внутри фирмы "1С" наши письма с просьбами читают и анализируют. А также, полагаю, они просматривают публикации на Инфостарте.

 
 Про циклы

 В языке 1С платформы "1С:Предприятие 8" на данный момент существует три вида цикла:

  • Цикл "Для" по счетчику, от меньшего к большему, с неизменным шагом +1;
  • Цикл "Для каждого" для коллекций, поддерживающих перебор (большинство коллекций);
  • Цикл "Пока" по условию (только в начале цикла).

И для решения основных задач этого достаточно. А какие виды циклов существуют ещё?

  • Цикл "Для" по счетчику, с настраиваемым шагом (см. язык BASIC)
  • Цикл "Для" от большего к меньшему (с отрицательным шагом -1, или настраиваемым, см. язык PASCAL)
  • Цикл "Делай ... Пока" по условию (в конце цикла, так что цикл выполнится не менее 1 раза, см. язык PASCAL)
  • Существуют также более сложные варианты циклов (см. язык С и все его "потомки").


Однажды, написав статью, расписывающую достоинства 1С, я упомянул среди недостатков - "мне не хватает обратного цикла". При этом, столкнулся с непониманием - "а зачем вообще нужен обратный цикл?". Сегодня я отвечу на этот вопрос.
Итак...

Рассмотрим задачу: 
Есть таблица значений с колонкой, в которой хранятся числа. Требуется удалить все строки, в которых в указанной колонке хранятся четные значения.
Для моделирования такой таблицы и проверки результата подойдёт следующий код:

ТЗ = новый ТаблицаЗначений;
ТЗ.Колонки.Добавить("Номер", новый ОписаниеТипов("Число"));
Массив = СтрРазделить("1, 1, 2, 1, 4, 6, 1, 1, 1, 8, 10, 1", ", ", Ложь);
Для каждого НомерСтрокой из Массив Цикл
	ТЗ.Добавить().Номер = Число(НомерСтрокой);
КонецЦикла;

Сообщить("Исходник: " + СтрСоединить(ТЗ.ВыгрузитьКолонку("Номер"), ", "));

// место вставки обработчика

Сообщить("Результат: " + СтрСоединить(ТЗ.ВыгрузитьКолонку("Номер"), ", "));

Имя переменной таблицы "ТЗ", имя колонки "Номер";


Попробуем решить данную задачу "в лоб":

Для сч=0 По ТЗ.Количество()-1 Цикл
	Если ТЗ[сч].Номер % 2 = 0 Тогда
		ТЗ.Удалить(сч);
	КонецЕсли;
КонецЦикла;

Попытка выполнить данный код приведет к исключению: "Индекс находится за границами массива" (да, да, именно "массива" - такую ошибку выдаёт платформа).

 
 Причина ошибки

Причина ошибки в том, что выражение "ТЗ.Количество()-1" рассчитывается только один раз до начала выполнения цикла, а не на каждой итерации (это задействует меньше вычислений и оптимально для большинства случаев использования "Для").
А, т.к. внутри цикла мы удаляем элементы коллекции, то размер этой коллекции тоже уменьшается. В итоге, счетчик выходит за пределы нашей коллекции и попытка чтения элемента приводит к ошибке.

 

Попробуем реализовать это через цикл "Пока"

сч = 0;
Пока сч<ТЗ.Количество() Цикл
	Если ТЗ[сч].Номер % 2 = 0 Тогда
		ТЗ.Удалить(сч);
	КонецЕсли;
	сч = сч + 1;
КонецЦикла;

Теперь мы проверяем Количество() при каждой итерации, что неоптимально в плане вычислительных ресурсов, но позволяет избежать выхода за границы. Вместо этого, можно присвоить ТЗ.Количество() некоторой переменной, сверять сч с ней, и уменьшать её когда удаляем строку. Это будет оптимальнее, но на несколько строк кода больше (а чем больше строк, тем сложнее потом будет его читать и разбирать).
Этот код уже выполнится.
Но в результате выдаст:
Исходник: 1, 1, 2, 1, 4, 6, 1, 1, 1, 8, 10, 1
Результат: 1, 1, 1, 6, 1, 1, 1, 10, 1

 
 Почему удалилось не всё?

Почему удалились не все чётные числа? Давайте разберем пошагово:
сч = 0: Массив значений в колонке: [1, 1, 2, 1, 4, 6, 1, 1, 1, 8, 10, 1], значение в ячейке = 1, пропускаем
сч = 1: Массив значений в колонке: [1, 1, 2, 1, 4, 6, 1, 1, 1, 8, 10, 1], значение в ячейке = 1, пропускаем
сч = 2: Массив значений в колонке: [1, 1, 2, 1, 4, 6, 1, 1, 1, 8, 10, 1], значение в ячейке = 2, удаляем, массив сместился на 1 влево
сч = 3: Массив значений в колонке: [1, 1, 1, 4, 6, 1, 1, 1, 8, 10, 1],     значение в ячейке = 4, удаляем, массив сместился на 1 влево
сч = 4: Массив значений в колонке: [1, 1, 1, 6, 1, 1, 1, 8, 10, 1],         значение в ячейке = 1, пропускаем (!)
сч = 5: Массив значений в колонке: [1, 1, 1, 6, 1, 1, 1, 8, 10, 1],         значение в ячейке = 1, пропускаем
сч = 6: Массив значений в колонке: [1, 1, 1, 6, 1, 1, 1, 8, 10, 1],         значение в ячейке = 1, пропускаем
сч = 7: Массив значений в колонке: [1, 1, 1, 6, 1, 1, 1, 8, 10, 1],         значение в ячейке = 8, удаляем, массив сместился на 1 влево
сч = 8: Массив значений в колонке: [1, 1, 1, 6, 1, 1, 1, 10, 1],             значение в ячейке = 1, пропускаем
сч = 9, сч=ТЗ.Количество(), цикл завершен
(красным выделены значения в строке [сч])

Обратите внимание, когда рядом стоят два четных числа, то после удаления строки - второе число смещается на 1 влево, при этом, счетчик увеличивается на 1 и, получается, перескакивает это число.

Такое происходит не только когда два четных числа стоят рядом. Обратите внимание, что когда сч=2 тоже происходит "перескакивание" через 1 значение, но т.к. оно является нечетным и всё равно не должно было быть удалено, то в результате выполнения это незаметно.

 


А как себя поведёт цикл "Для каждого"?

Для Каждого Строка из ТЗ Цикл
	Если Строка.Номер % 2 = 0 Тогда
		ТЗ.Удалить(Строка);
	КонецЕсли;
КонецЦикла;

Этот код уже выполниться без ошибок. Но результат выдаст точно такой-же, как и цикл "Пока"
Исходник: 1, 1, 2, 1, 4, 6, 1, 1, 1, 8, 10, 1
Результат: 1, 1, 1, 6, 1, 1, 1, 10, 1


Как бы решалась эта задача, если бы у нас был обратный цикл?
"Для" со счетчиком -1 решил бы эту проблему:

Для ТЗ.Количество()-1 По сч=0 Цикл //обратный или шаг -1
	Если ТЗ[сч].Номер % 2 = 0 Тогда
		ТЗ.Удалить(сч);
	КонецЕсли;
КонецЦикла;

Т.к. обход коллекции выполняется в обратном порядке, удаление элемента смещает массив относительно счетчика цикла, но и счетчик смещается в том-же направлении.


 

Так как-же быть?
А теперь, варианты костылей, с помощью которых решается эта задача (все они приводят к желаемому результату):

1. Аналог решения, встречаемый в типовых конфигурациях 1С:

МассивНаУдаление = новый Массив;

Для каждого Строка из ТЗ Цикл
	Если Строка.Номер % 2 = 0 Тогда
		МассивНаУдаление.Добавить(Строка);
	КонецЕсли;
КонецЦикла;

Для каждого Строка из МассивНаУдаление Цикл
	ТЗ.Удалить(Строка);
КонецЦикла;

Нужны комментарии?


2. Вариант с циклом "Пока", но со смещением или счетчика или строки

сч = 0;
Пока сч<ТЗ.Количество() Цикл
	Если ТЗ[сч].Номер % 2 = 0 Тогда
		ТЗ.Удалить(сч);
	Иначе
		сч = сч + 1;
	КонецЕсли;
КонецЦикла;


3. Еще один вариант с циклом "Пока"

сч = 0;
Пока сч<ТЗ.Количество() Цикл
	Если ТЗ[сч].Номер %2 = 0 Тогда
		ТЗ.Удалить(сч);
		сч = сч - 1;
	КонецЕсли;
	сч = сч + 1;
КонецЦикла;


4. Эмуляция обратного цикла с помощью цикла "Пока"
(сам я, чаще всего, в коде делаю именно так, т.к. это минимум лишних операций и уменьшение счетчика в первой-же строке внутри цикла гарантирует, что если в теле цикла будет "Продолжить" - не произойдёт зацикливание)

сч = ТЗ.Количество();
Пока сч>0 Цикл
	сч = сч - 1;
	Если ТЗ[сч].Номер % 2 = 0 Тогда
		ТЗ.Удалить(сч);
	КонецЕсли;
КонецЦикла;


5. Эмуляция обратного цикла с помощью цикла "Для"
(а этот метод мне попался недавно, и заинтересовал. Хотя количество операций смены знака здесь немалое, код смотрится весьма лаконично)

Для сч = -ТЗ.Количество() + 1 По 0 Цикл
	Если ТЗ[-сч].Номер % 2 = 0 Тогда
		ТЗ.Удалить(-сч);
	КонецЕсли;
КонецЦикла;

Ну да, цикл "Для" хоть и по счетчику +1, но нормально работает с отрицательными числами.

6. Еще такой вариант встречается часто:

Количество = Коллекция.Количество();
Для Номер = 1 По Количество Цикл
	ОбратныйИндекс = Количество - Номер;
	Коллекция.Удалить(ОбратныйИндекс);
КонецЦикла;

Автор: (70)  PerlAmutor 29.05.23 06:49

 
Резюмирую

Это упрощенная вариация задач, периодически встречающихся в разработке, к задачам такого-же плана относятся задачи вида "удалить все цифры из строки", "удалить дублирующиеся элементы в коллекции". Даже сама фирма 1С сталкивается с подобными задачами при разработке своих типовых решений. И задача очень лаконично решается через обратный цикл. Вот почему мне бы хотелось видеть его в составе конструкций языка 1С (а заодно, можно бы и "Для каждого" допилить, чтобы не пропускал элементы коллекции).

См. также

Поинтегрируем: сервисы интеграции – новый стандарт или просто коннектор?

Обмен между базами 1C Администрирование СУБД Механизмы платформы 1С Платформа 1С v8.3 Бесплатно (free)

В платформе 8.3.17 появился замечательный механизм «Сервисы интеграции». Многие считают, что это просто коннектор 1С:Шины. Так ли это?

11.03.2024    4525    dsdred    53    

71

Как готовить и есть массивы

Механизмы платформы 1С Платформа 1С v8.3 Бесплатно (free)

Все мы используем массивы в своем коде. Это один из первых объектов, который дают ученикам при прохождении обучения программированию. Но умеем ли мы ими пользоваться? В этой статье я хочу показать все методы массива, а также некоторые фишки в работе с массивами.

24.01.2024    5294    YA_418728146    25    

63

Планы обмена VS История данных

Обмен между базами 1C Механизмы платформы 1С Платформа 1С v8.3 Бесплатно (free)

Вы все еще регистрируете изменения только на Планах обмена и Регистрах сведений?

11.12.2023    6409    dsdred    36    

111

1С-ная магия

Механизмы платформы 1С Бесплатно (free)

Язык программирования 1С содержит много нюансов и особенностей, которые могут приводить к неожиданным для разработчика результатам. Сталкиваясь с ними, программист начинает лучше понимать логику платформы, а значит, быстрее выявлять ошибки и видеть потенциальные узкие места своего кода там, где позже можно было бы ещё долго медитировать с отладчиком в поисках источника проблемы. Мы рассмотрим разные примеры поведения кода 1С. Разберём результаты выполнения и ответим на вопросы «Почему?», «Как же так?» и «Зачем нам это знать?». 

06.10.2023    18473    SeiOkami    46    

118

Дефрагментация и реиндексация после перехода на платформу 8.3.22

Механизмы платформы 1С Платформа 1С v8.3 Бесплатно (free)

Начиная с версии платформы 8.3.22 1С снимает стандартные блокировки БД на уровне страниц. Делаем рабочий скрипт, как раньше.

14.09.2023    12088    human_new    27    

74

Валидация JSON через XDTO (включая массивы)

WEB-интеграция Универсальные функции Механизмы платформы 1С Платформа 1С v8.3 Конфигурации 1cv8 Бесплатно (free)

При работе с интеграциями рано или поздно придется столкнуться с получением JSON файлов. И, конечно же, жизнь заставит проверять файлы перед тем, как записывать данные в БД.

28.08.2023    8821    YA_418728146    6    

141

Внешние компоненты Native API на языке Rust - Просто!

Механизмы платформы 1С Платформа 1С v8.3 Конфигурации 1cv8 Бесплатно (free)

Внешние компоненты для 1С можно разработывать очень просто, пользуясь всеми преимуществами языка Rust - от безопасности и кроссплатформенности до удобного менеджера библиотек.

20.08.2023    6279    sebekerga    54    

94

Все скопируем и вставим! (Буфер обмена в 1С 8.3.24)

Механизмы платформы 1С Платформа 1С v8.3 Конфигурации 1cv8 Бесплатно (free)

Рассмотрим новую возможность 8.3.24 и как её можно эффективно использовать

27.06.2023    15986    SeiOkami    31    

103
Комментарии
В избранное Подписаться на ответы Сортировка: Древо развёрнутое
Свернуть все
1. salexdv 2327 08.09.22 08:34 Сейчас в теме
Предлагаю не мелочиться, а сразу попросить у 1С фильтры для коллекций, чтобы делать что-то вроде такого

НоваяТаблица = Таблица.Фильтр((СтрокаТЧ) => СтрокаТЧ.Номер % 2 = 0)


И сортировку туда же

Таблица.Сортировать((Строка0, Строка1) => Строка0.Номер - Строка1.Номер)
deletel; brr; CodeNull; LimarenkoA; 7OH; kser87; Бубузяка; VladC#; Altez50; Поручик; Irwin; Sedaiko; kirabr; CyberCerber; cleaner_it; anosin; artbear; Windsor77; Shmell; Артано; SAShikutkin; +21 Ответить
3. SAShikutkin 5 08.09.22 09:00 Сейчас в теме
(1)Аналог LINQ - действительно, было бы интересно)
11. tormozit 7136 08.09.22 09:26 Сейчас в теме
(1) Как их отлаживать? Если выражение достаточно сложное, то захочется пощупать его части для конкретной строки (например на которой возникла ошибка). Как это будет выглядеть?
12. Артано 760 08.09.22 09:29 Сейчас в теме
(11) Я думаю, что в скобках отдельная функция написанная в одну строку. Соответственно отладка будет в той самой функции. По крайней мере в других языках для переопределения условий сортировки/фильтрации пишется отдельная функция.
14. tormozit 7136 08.09.22 09:33 Сейчас в теме
(12) Если будет отдельная функция, то ОК. Технически нам и сейчас мешает ничто сделать такой механизм на прикладном уровне. Только придется делать явный цикл и вызов функции будет компилироваться при каждом его проходе, что несомненно внесет ощутимое замедление.
16. Артано 760 08.09.22 09:35 Сейчас в теме
(14) Поэтому граждане и просят, чтобы работало "искаропки". Тогда будет оптимизировано на уровне платформы. Хотя, полагаю, что сложный алгоритм сравнения не оптимизировать и придется применять функцию к каждому элементу.
58. ubnkfl 14.09.22 18:31 Сейчас в теме
(14)
мешает ничто

"Мешает ничто" - потому что вам не нравится двойное отрицание в русском языке? :)
59. tormozit 7136 14.09.22 22:41 Сейчас в теме
(58) Ты должен последовать моему примеру. Ведь ты и сам об этом задумывался и хотел попробовать. Что тебе мешает?
75. brr 182 05.12.23 16:24 Сейчас в теме
(14)Можно собрать текст цикла с вызовом функции и один раз "скомпилировать".
13. salexdv 2327 08.09.22 09:32 Сейчас в теме
(11) Это просто сокращенная запись такого

Функция ФильтрПоЧетным(СтрокаТЧ)

    Возврат СтрокаТЧ.Номер % 2 = 0;

КонецФункции

Таблица.Фильтр(ФильтрПоЧетным);
21. DrAku1a 1679 08.09.22 09:51 Сейчас в теме
(1) Не в таком виде, а в виде функции, передаваемой как параметр - можно было бы.
Мне нравится рекомендация 1С писать понятный код, даже используя большее количество строк кода.

Т.е. вместо:
СтруктураДанных = новый Структура("Наименование, Представление, Вид, Модифиукатор", "Наименование", "Представление", ...

делать многострочное:
СтруктураДанных = новый Структура;
СтруктураДанных.Вставить("Наименование", "Наименование");
СтруктураДанных.Вставить("Представление", "Представление");
...

второй вариант - нагляднее.
cleaner_it; Артано; +2 Ответить
25. salexdv 2327 08.09.22 09:56 Сейчас в теме
(21) Я с одной стороны согласен, а с другой нет. Конечно, если функция для фильтрации/сортировки сложная, то нет смысла записывать её в одну строку, но вот если она простая, как в моём примере, тогда это проще читается. Просто для нас, как для 1Сников это выглядит непривычно.
33. JohnyDeath 301 09.09.22 09:28 Сейчас в теме
(1) Можно еще вспомнить великолепную 1С++ для 7.7. Там есть очень крутой объект под названием ИндексированнаяТаблица, в которой можно удалять по Индексу с учетом наложенных на него фильтров. А еще у этого объект есть даже Левые и Правые соединения, разности, итоги по узлу и пр..
Вообще мощная вещь, как и весь 1С++
CheBurator; 7OH; salexdv; Артано; DrAku1a; +5 Ответить
48. VladC# 64 12.09.22 08:55 Сейчас в теме
(1) Очень напминает лямбды из java, если бы что-то подобное появилось в 1с, то это был бы огромный шаг вперёд, но у 1с своё видение того что нужно, так что даже мечтать не стоит о таком.
65. Evil Beaver 8107 30.09.22 12:05 Сейчас в теме
(1) Предлагаю не ждать милостей от судьбы, а портировать на 1С библиотеку fluent от 1Script https://github.com/oscript-library/fluent
alei1180; salexdv; +2 Ответить
72. tormozit 7136 24.06.23 16:32 Сейчас в теме
(1) Попробовал слепить функцию фильтрации коллекции из того что имеем https://infostart.ru/1c/articles/1887014/
It-developer; salexdv; +2 Ответить
2. ixijixi 1775 08.09.22 08:50 Сейчас в теме
Как бы решалась эта задача, если бы у нас был обратный цикл?

Я возможно невнимательно читал, но в чем проблема? Обратный цикл в 1С есть и отлично работает
Для Сч = 1 - ТаблицаЗначений.Количество() По 0 Цикл
	ТаблицаЗначений.Удалить(ТаблицаЗначений.Получить(-Сч));
	// или
	ТаблицаЗначений.Удалить(-Сч);
КонецЦикла;
ketr; sivin-alexey; user811769; Revachol; user1792010; Sergey_Borisovi4; akR00b; Lobion; NiGMa; Yashazz; smit1c; Irwin; SerVer1C; insurgut; paybaseme; kuzev; CyberCerber; cleaner_it; mikl79; 0x00; 7o2uYXg; user1559729; tormozit; +23 Ответить
7. Артано 760 08.09.22 09:12 Сейчас в теме
(2) Если поведение платформы не меняли, то такой цикл не выполнит ни одной итерации.

По сабжу автора - данный вопрос удобно решается обратным циклом, но сам пример может быть решен более оптимально (с точки зрения производительности) без поитерационного удаления строк. Я имею ввиду метод Скопировать().
9. tormozit 7136 08.09.22 09:17 Сейчас в теме
(7) Цикл рабочий. Я тоже его использую. Читай документацию.
Артано; +1 Ответить
10. Артано 760 08.09.22 09:21 Сейчас в теме
(9) Не разглядел два костыля в алгоритме. Согласен, рабочий. Но не очевидный. Документация тут вообще не причем, это просто своеобразный алгоритм, который будет примерно одинаковым на любом языке
8. tormozit 7136 08.09.22 09:15 Сейчас в теме
(2) У меня даже шаблон есть такой
Для Индекс = 1 - <?"Коллекция">.Количество() По 0 Цикл // Обратный обход
	<?"Элемент коллекции"> = <?"Коллекция">[-Индекс];
	Если <?> Тогда
		<?"Коллекция">.Удалить(<?"Элемент коллекции">);
	КонецЕсли;
КонецЦикла;
It-developer; ketr; Serg2000mr; СергейК; Yashazz; Cmapnep; fancy; simgo83; Windsor77; MVK80; DrAku1a; zqzq; +12 Ответить
35. Cmapnep 18 09.09.22 09:50 Сейчас в теме
(8)
Для Индекс = 1 - .Количество() По 0 Цикл // Обратный обход
= [-Индекс];
Если Тогда
.Удалить();
КонецЕсли;
КонецЦикла;


А можешь поделиться своим файлом шаблонов - уверен там еще много интересного и полезного найдется
15. DrAku1a 1679 08.09.22 09:33 Сейчас в теме
(2) Невнимательно. См. в конце: "5. Эмуляция обратного цикла с помощью цикла "Для""
17. ixijixi 1775 08.09.22 09:36 Сейчас в теме
(15) В чем тогда суть статьи "Не хватает обратного цикла", если обратный цикл есть?
CodeNull; Yashazz; 0x00; +3 Ответить
20. Артано 760 08.09.22 09:45 Сейчас в теме
(17) Его нет, но его можно эмулировать. Такая эмуляция на мой взгляд есть хардкод. Нативно отрицательный шаг счетчика невозможен
Fox-trot; unknown181538; Windsor77; DrAku1a; +4 Ответить
22. DrAku1a 1679 08.09.22 09:52 Сейчас в теме
(20) Да. Именно про это статья.
49. ixijixi 1775 12.09.22 10:34 Сейчас в теме
(20) Что такое нативно отрицательный шаг счетчика?
50. Артано 760 12.09.22 10:39 Сейчас в теме
(49) Здесь могла быть запятая, но переводится как: "искаропки в 1с нет отрицательного шага счетчика".
51. ixijixi 1775 12.09.22 10:40 Сейчас в теме
(50) Может тогда для примера - где он есть искаропки? Я хоть сравню)
52. Артано 760 12.09.22 10:46 Сейчас в теме
(51) Си и потомки (через декремент) , Паскаль/Делфи, Бейсик и потомки. Множество их.
Питон еще вспомнил. В общем, масса примеров - щупайте =)
53. ixijixi 1775 12.09.22 11:28 Сейчас в теме
(52) Бегло загуглил. Дошло, спасибо)
28. unknown181538 151 08.09.22 18:13 Сейчас в теме
(2) Вариант лаконичны и рабочий, но менее читаемый. Обратный цикл был более прозрачным.
4. quazare 3586 08.09.22 09:08 Сейчас в теме
Используйте функцию "РазложитьСтрокуВМассивПодстрок" - так будет "по-книжному"
18. DrAku1a 1679 08.09.22 09:38 Сейчас в теме
(4) СтрРазделить() - уже полноценная функция платформы (начиная с версии 8.3.6). До этого были только возможности БСП.
Yashazz; paybaseme; quazare; +3 Ответить
29. AntonProgma 46 08.09.22 22:59 Сейчас в теме
(18) главное - помнить о её ковартстве и не рассчитывать на многосимвольный разделитель
ixijixi; DrAku1a; Поручик; +3 Ответить
31. quazare 3586 09.09.22 06:17 Сейчас в теме
(18) вы правы! вообще материал хороший у вас - эдакая гимнастика для извилин.
5. MikhailDr 08.09.22 09:09 Сейчас в теме
Постоянно перебираю таблицы через Сч = Сч - 1; Проблемы не вижу, может я чего-то не понимаю?
19. DrAku1a 1679 08.09.22 09:45 Сейчас в теме
(5) Во-первых, это не так наглядно и интуитивно понятно, как цикл "Для".
Во-вторых, стоит один раз забыть написать эту самую "Сч = Сч - 1" и запустить код на исполнение... и Вы увидите, что проблема имеет место (или, если не делаете "Сч = Сч - 1" в самом начале цикла "Пока" и в цикле по какому-либо условию будет "Продолжить" - можно, также, получить зацикливание).
23. MikhailDr 08.09.22 09:53 Сейчас в теме
(19)
Во-вторых, стоит один раз забыть написать эту самую "Сч = Сч - 1"


Если так рассуждать, то надо от цикла "Пока" отказываться. Ведь там тоже можно вызвать зацикливание, это такой себе довод.

Что до интуитивности то конкретно здесь это вопрос опыта и привычки, для меня это абсолютно интуитивная конструкция.

Я в целом не имею ничего против обратных циклов, это небольшой синтаксический сахар. Но он очень небольшой, есть задачи гораздо более приоритетные в рамках развития платформы.
26. DrAku1a 1679 08.09.22 10:36 Сейчас в теме
(23)
Если так рассуждать, то надо от цикла "Пока" отказываться.
Цикл "Пока" хорошо подходит для обработки выборок (Пока Выборка.Следующий() Цикл).
60. DrAku1a 1679 19.09.22 08:53 Сейчас в теме
(23)
есть задачи гораздо более приоритетные в рамках развития платформы
можете озвучить?
в первую очередь интересует то, что касается языка 1С. Но и платформенные недоработки, и прочее - тоже интересно.
Как сказано в заголовке, я планирую цикл статей таких написать. Но, если это будет нечто большее, чем ИМХО - думаю, будет интереснее.

Например, я хочу разобрать пару типовых конфигураций и посмотреть почему они такие здоровые. Можно ли их сделать "легче" и что это даст.
dvsidelnikov; +1 Ответить
61. MikhailDr 19.09.22 09:17 Сейчас в теме
(60) Тут конечно надо хорошо подумать, но навскидку я бы назвал пару вещей

1. Доработка механизма расширений. Тут много всего, в идеале расширения должны полностью повторять весь функционал основной конфигурации. Как пример - добавить тип "ЛюбаяСсылка"

2. Доработка контекстной подсказки в конфигураторе. Например создав таблицу в процедуре вам будет доступна контекстная подсказка только в рамках этой процедуры. Но если передать таблицу в другую процедуру, то там уже подсказка недоступна.
62. DrAku1a 1679 19.09.22 10:52 Сейчас в теме
(61) Тип "ЛюбаяСсылка" уже добавлен, но нужен режим совместимости 8.3.20 и выше. Проблема в том, что текущий режим совместимости типовых конфигураций 8.3.17-8.3.18, и с учетом того, как быстро поднимают этот режим - до использования его, например, с УТ 11 или БП 3, ожидать нужно ещё где-то 2 года.

Механизм расширений ещё сырой и активно развивается. Как и всем нововведения 1С, нужно время на адаптацию.

Из моих пожеланий к нему я бы выделил "возможность видеть другие расширения" - т.е. иерархию расширений (механизм "расширение на расширение"), или директиву "использует" с указанием других расширений и их версий и заимствования объектов из других расширений.

По проводу (2), есть мысль что сказать. Тут несколько сложнее ситуация, и связана она с отсутствием типизации параметров (процедур и функций). Это с одной стороны удобно.
6. Evg-Lylyk 4559 08.09.22 09:11 Сейчас в теме
(0) По описанному примеру: ИМХО вариант с массивом простой и понятный. Жаль что Удалить() не работает с массивом.
unknown181538; +1 Ответить
24. SerVer1C 748 08.09.22 09:53 Сейчас в теме
Требуем ООП , LINQ, дженерики и лямбды !!! Ну хотя бы инкремент чтобы завезли (причем в байт-коде он присутствует отдельным оп-кодом).
27. triviumfan 92 08.09.22 12:53 Сейчас в теме
Хоть тема и простая, но было интересно) спасибо
30. Pavel_Vladivostok 58 09.09.22 05:52 Сейчас в теме
Если таблица объемная, я бы предпочел выбрать не удаляемые строки запросом и скопировать исходную таблицу указав массив правильных строк, избегая при этом циклы вообще.
32. Артано 760 09.09.22 08:20 Сейчас в теме
(30) Угу. Писал об этом в (7)
34. JohnyDeath 301 09.09.22 09:45 Сейчас в теме
Еще вариант:
тз = Новый ТаблицаЗначений;
//.... наполнение тз ....
имяСлужебнойКолонки = "_Удалить_";
тз.Колонки.Добавить(имяСлужебнойКолонки, Новый ОписаниеТипов("Булево"));
Для Каждого строкаТЗ Из тз Цикл
	строкаТЗ._Удалить_ = (строкаТЗ.Номер % 2 = 0);	
КонецЦикла;
отбор = Новый Структура(имяСлужебнойКолонки, Ложь);
тз = тз.Скопировать(отбор);
тз.Колонки.Удалить(имяСлужебнойКолонки);
Показать
36. DrAku1a 1679 09.09.22 10:05 Сейчас в теме
(34) А чего мелочиться, давайте сделаем копию таблицы через ТЗ.ВыгрузитьКолонки() и заполним её строками с нечетными числами? (Это, мягко говоря, неоптимально).
38. JohnyDeath 301 09.09.22 10:16 Сейчас в теме
(36) возможно такой вариант будет даже более производительный, чем все вышеперечисленные.
Но надо, конечно же, проверять
39. DrAku1a 1679 09.09.22 10:31 Сейчас в теме
(38) Насколько я понимаю работу менеджеров памяти, выделять память под новые объекты им несколько сложнее и дольше, чем освобождать (по факту, при работе кода память не освобождается, а просто помечается неиспользуемой). При создании новой колонки, новой таблицы, нового массива - нужно ещё найти место где разместить эти объекты. Но, можно проверить, в этом плане 1С может удивить.
37. JohnyDeath 301 09.09.22 10:13 Сейчас в теме
А вообще нет с классическим "GoTo" во втором варианте
сч = 0;
Пока сч<ТЗ.Количество() Цикл
~Перепроверка:
	Если ТЗ[сч].Номер % 2 = 0 Тогда
		ТЗ.Удалить(сч);
		Перейти ~Перепроверка;
	КонецЕсли;
	сч = сч + 1;
КонецЦикла;
Показать
40. DrAku1a 1679 09.09.22 10:35 Сейчас в теме
(37) Оператор goto в языках высокого уровня является объектом критики, поскольку чрезмерное его применение приводит к созданию нечитаемого «спагетти-кода» (источник: статья на Википедии). Поэтому, варианты с безусловным переходом мною даже не рассматривались.
maksa2005; +1 Ответить
41. JohnyDeath 301 09.09.22 10:40 Сейчас в теме
(40) и что здесь черезмерного? По-моему этот код намного проще читается, чем большинство описанных.
Да, goto нежелателен. Но все-таки действовать надо по ситуациям, а не по рекомендациям википедии и ИТС
Хотя этот вариант будет скорее всего самый долгий
brr; lunjio; Артано; +3 Ответить
42. DrAku1a 1679 09.09.22 11:06 Сейчас в теме
(41) Видимо, неправильно пояснил. Для меня уже за правило стало - не использовать операторы безусловного перехода. Именно из-за критики. Когда-то давно преподаватель информатики озвучил такое мнение: "Квалификация программиста обратно-пропорциональна использованию им оператора безусловного перехода" (это неточная цитата). Написать любой алгоритм возможно без GoTo.
Вот, нашел материал по теме: https://studfile.net/preview/1444532/page:12/
Fox-trot; +1 Ответить
43. JohnyDeath 301 09.09.22 11:09 Сейчас в теме
(42) ровно как и написать любой алгоритм без обратных циклов )
Артано; +1 Ответить
44. DrAku1a 1679 09.09.22 11:11 Сейчас в теме
(43) вот только критики обратных циклов не находил ))
Fox-trot; +1 Ответить
45. Артано 760 09.09.22 11:46 Сейчас в теме
(42) Согласен с Джонни. Если код станет нагляднее и лаконичнее с GOTO, то не вижу оснований фанатично его отрицать. Тот же Дейкстра, считающийся ненавистником безусловных переходов, допускал их ограниченное использование.
67. CheBurator 3119 31.10.22 22:54 Сейчас в теме
(42)
"Квалификация программиста обратно-пропорциональна использованию им оператора безусловного перехода"

этот ваш "перпедователь" видно никогда на ассемблере не программировал. там готу - в порядке вещей, типа
BR 14 - переход по адресу, содержащемуся в 14 регистре...
68. DrAku1a 1679 02.11.22 05:56 Сейчас в теме
(67) На то он и ассемблер. Язык низкого уровня, максимально близкий непосредственно к машинному коду.
Речь о языках более высокого уровня, гораздо более абстрактных, не претендующих на максимально быстрый код (хотя и стремящихся к этому), минимальные размеры самого приложения и оптимальности использования памяти в переменных.
76. brr 182 05.12.23 16:28 Сейчас в теме
47. Art39_ 12.09.22 00:26 Сейчас в теме
5 вариант интересный, возьму на вооружение, жаль раньше не встречал.
46. PerlAmutor 129 09.09.22 17:52 Сейчас в теме
Использую 5-ый вариант цикла наверное уже как год, по поводу и без повода. Однажды увидел в типовой, понравилось.
54. Arxxximed 34 12.09.22 19:17 Сейчас в теме
По моему в 1С ооочень много чего не хватает, и приходится эмулировать. Синтаксический сахар для разработчиков 1С это зло )).
За удобствами вам не в 1С.
За удобствами вам в Python
55. DrAku1a 1679 13.09.22 03:41 Сейчас в теме
(54) В языке программирование - возможно. Хотя, по мне, синтаксис "вот тут отступ - это значит блок ("для", "если")" - ну, такое... Я не хочу сказать, что 1С лучше чем Python, ровно как и обратное. Свои достоинства и недостатки есть в каждом языке и в каждой среде.
Платформа 1С - это не только и не столько язык программирования. Это скорее - конструктор (конфигуратор), внутри которого много конструкторов поменьше (запросов, форматной строки, печатных форм и т.п.). Язык же - инструмент, который помогает работать созданным в конструкторах механизмам.
Прикрепленные файлы:
57. Arxxximed 34 14.09.22 12:07 Сейчас в теме
(55) Да, отступы или скобки - на вкус и цвет, мне отступы вполне зашли. Но по сравнению с Цикл КонецЦикла, Если КонецЕсли, КонецФункции... Уж лучше VBAшное END. Меньше писанины. И один черт отступы то есть во всех языках при форматировании )))))

Но суть не про это, а про синтаксический сахар Ну извините стандартное , идущее с незапамятных времен
переменная += 1;
могли бы уже добавить.

Про платформу - Вы правы, но речь идет именно же про язык. Автору не понравилось что нету обратного Цикла
Мне же не нравится что например питоновское СтрТекст[2:-2] приходится писать в Сред(СтрТекст, 2 , СтрДлина(СтрТекст-4)). Долго писать непонятно читать.
56. Артано 760 14.09.22 05:51 Сейчас в теме
(54) Примерно то же самое говорили разработчики на 7.7 когда появилась восьмёрка. Я например, игнорировал 1с, пока не вышла 8.2. Только после этого пошел в 1с "на полный штат".
63. pm74 199 25.09.22 19:56 Сейчас в теме
внимательно не вчитывался , не заметил такого варианта

Для _сч = (ТЗ.Количество()-1)*-1  По 0 Цикл 
       сч = -_сч;
...
64. DrAku1a 1679 26.09.22 07:49 Сейчас в теме
(63) см.
5. Эмуляция обратного цикла с помощью цикла "Для"
66. Heinz 12.10.22 16:28 Сейчас в теме
(1)Т.е. вы сразу и лямбды попросили, а заодно и функции первого класса.
69. heroy 25.11.22 12:07 Сейчас в теме
(66) Замыкания это удобно, открывает путь в новый мир, а по сути это всего лишь синтаксический сахар для шаблона функтор, да, еще нужно 2 шага сделать, анонимные функции и в конце концов лябды, но это все еще сахар
70. PerlAmutor 129 29.05.23 06:49 Сейчас в теме
Еще такой вариант встречается часто:

		Количество = Коллекция.Количество();
		Для Номер = 1 По Количество Цикл
			ОбратныйИндекс = Количество - Номер;
			Коллекция.Удалить(ОбратныйИндекс);
		КонецЦикла;
71. DrAku1a 1679 29.05.23 12:37 Сейчас в теме
(70) Да, и в типовых тоже встречается. Добавлю.
73. user1707144 26.10.23 10:50 Сейчас в теме
	Массив = Новый Массив;
	Массив.Добавить("Красный");
	Массив.Добавить("Жёлтый");
	Массив.Добавить("Зелёный");
	
	Индекс = Массив.ВГраница();
	Пока Индекс >= 0 Цикл
		
		Сообщить(Массив[Индекс]);
		Индекс = Индекс - 1;
		
	КонецЦикла;
Показать
74. DrAku1a 1679 27.10.23 06:01 Сейчас в теме
(73) см "Попробуем реализовать это через цикл "Пока""
Если индекс уменьшать в конце цикла, то существует шанс получить зацикливание - если тело цикла будет большим (или станет большим со временем), и в теле цикла будет по какому-то условию использоваться "Продолжить":
    Массив = Новый Массив;
    Массив.Добавить("Красный");
    Массив.Добавить("Жёлтый");
    Массив.Добавить("Зелёный");
    
    Индекс = Массив.ВГраница();
    Пока Индекс >= 0 Цикл
        //код
        //код
        //код
        //код
        //код
        //код
        //код
        //код
        //код
        //код

        Если (КакоеТоУсловиеИстинно) Тогда
                Продолжить;
        КонецЕсли;


        //код
        //код
        //код
        //код
        //код
        //код
        //код
        //код
        //код
        //код
        //код
        //код

        Индекс = Индекс - 1;
        
    КонецЦикла;

Показать
Оставьте свое сообщение