Работа с абстрактным массивом

14.04.22

Разработка - Математика и алгоритмы

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

Скачать исходный код

Наименование Файл Версия Размер
Конфигурация
.cf 82,73Kb
1
.cf v1.0.6 82,73Kb 1 Скачать
Демо-база: сортировка дерева на форме в контексте клиента
.dt 78,69Mb
0
.dt v1.0.6 78,69Mb Скачать
Расширение
.cfe 12,71Kb
0
.cfe v1.0.6 12,71Kb Скачать

Оглавление

Массивы и абстрактные типы данных. 2

Абстрактные алгоритмы.. 2

Функции как объекты первого класса. 2

Сортировка массива. 2

Простые примеры использования. 3

Конструктор. 3

Сортировать (sort) 3

Отобрать (filter) 3

Отобразить (map) 3

Преобразовать (reduce) 3

Текучий интерфейс для абстрактного массива. 3

Мутации. 6

Конструктор абстрактного типа данных массив. 6

Функции первого порядка. 7

Пример повышенной сложности :] 7

Формирование списка подсистем.. 7

Реализация команды "Выбрать объекты подсистемы". 8

Поиск выбранной подсистемы.. 8

Формирование списка объектов метаданных по выбранной подсистеме. 9

Пометка объектов метаданных по выбранной подсистеме. 9

Вывод. 9

Поставка. 10


Все объекты окружающего нас мира реального или виртуального состоят из списков свойств. Базовым типом данных, описывающим списки в 1С является массив.

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

В мире программирования известны и другие абстрактные типы данных: Стек, Очередь, Список. Однако и они вполне могут быть реализованы на базе работы с массивом в 1С.

Массив в отличии от структуры данных, является абстрактным типом. На практике в работе с массивами выделяют следующие абстрактные алгоритмы: сортировка, преобразование, отбор и агрегирование.

Дело в том, что структура данных описывает определенную предметную область, а массив сам по себе не привязан к какой-либо области. Фактически имея базовый набор абстрактных алгоритмов любой исходный массив можно преобразовать в любую необходимую структуру данных. Если принять во внимание, что любой объект данных также можно представить в виде массива свойств, то получаем универсальные алгоритмы для решения любой задачи.

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

Функциональный подход подразумевает, что в языке есть функции первого класса. Такие функции можно передавать в другие функции наравне с обычными типами данных. В 1С нет поддержки такого рода функций, однако похожий механизм можно реализовать через выражения на языке 1С.

Наличие оператора Вычислить позволяет выполнить выражение на языке 1С. Эту возможность я и предлагаю рассмотреть для реализации абстрактных алгоритмов по работе с массивами.

Чего мне сильно не хватает в массивах на 1С - это метода сортировки. Казалось бы можно сортировать списки, даже по значению, сортировать таблицы значений, а вот массивы - нет!

Возможно именно отсутствие метода сортировки для массивов и сподвигло меня в конечном итоге к поиску такого решения, как представлено здесь.

Алгоритмы сортировки уже известны давно. Мне не пришлось даже ничего программировать, и я воспользовался публикацией по данной теме. Дальше мне оставалось лишь обобщить алгоритм для абстрактных структур данных. Так у меня появилась функция Сравнить. И здесь я снова ничего не придумал, а взял готовое решение из других языков программирования :)

Первые эксперименты произвели на меня эффект - алгоритм реально работал! :) Так я пришел к универсальному решению для 1С, когда массив с любыми объектами можно сортировать. Для массива с элементами простых типов реализация работает в базовой библиотеке.

Помимо сортировки в представленной библиотеке реализованы все основные абстрактные алгоритмы.

Фрукты = РаботаСМассивом.АТДМассив(СтрРазделить("вишня, арбузы, бананы", ", ", Ложь));
Фрукты.ДляКаждого("Сообщить(Элемент)");// [вишня, арбузы, бананы]
Фрукты.Сортировать();
Фрукты.ДляКаждого("Сообщить(Элемент)");// [арбузы, бананы, вишня]
Фрукты.Сортировать("Сравнить(Б, А)");// обратный порядок
Фрукты.ДляКаждого("Сообщить(Элемент)");// [вишня, бананы, арбузы]
Фрукты.Отобрать("СтрНайти(Элемент, ""а"") > 0");
Фрукты.ДляКаждого("Сообщить(Элемент)");// [арбузы, бананы]
Фрукты.Отобразить("ВРег(Лев(Элемент, 1)) + Прав(Элемент, СтрДлина(Элемент) - 1)");
Фрукты.ДляКаждого("Сообщить(Элемент)");// [Арбузы, Бананы]
Количество = Фрукты.Преобразовать("Накопитель + 1", 0);
Сообщить(Количество);// 2

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

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

Объектная модель также позволяет хранить свое состояние. Получается некоторая смесь объектно-ориентированного и функциональных парадигм. Из ООП здесь хранение данных и методов работы с ними в одном объекте - модели, а из функционального - реализация абстрактных алгоритмов. И все это в рамках языка 1С! 😊

Вот следующие примеры использования классического подхода и функционального при конструировании составного типа из строки и ссылки на справочник Номенклатуры:

МассивТипов = Новый Массив;
МассивТипов.Добавить(Тип("СправочникСсылка. _ДемоНоменклатура "));
МассивТипов.Добавить(Тип("Строка"));
ПараметрыСтроки = Новый КвалификаторыСтроки(20);
ДопустимыеТипы = Новый ОписаниеТипов(МассивТипов, , ПараметрыСтроки);

Конструктор на основе абстрактного массива:

ДопустимыеТипы = Новый ОписаниеТипов(РаботаСМассивом.АТДМассив()
	.Положить(Тип("СправочникСсылка._ДемоНоменклатура"))
	.Положить(ОбщегоНазначения.ОписаниеТипаСтрока(20))
	.ВМассив());

Чтобы еще более разобраться в преимуществах функциональной парадигмы разберем пример. Вначале решим задачу в классическом процедурном стиле, затем в функциональном.

Итак, на входе у нас имеется файл в формате похожем на упрощенный markdown. Необходимо на выходе сформировать отчет в формате табличного документа 1С.

В классическом подходе создадим цикл прохода по строкам файла. Для каждой строки определим область табличного документа и выведем её.

Тоже решение в функциональном стиле подразумевает на вход подать файл, а на выходе получить табличный документ. Чтобы не переусложнять на вход начальной функции подготовим массив строк исходного файла. Далее преобразуем массив строк в массив областей табличного документа и наконец выведем области в табличный документ.

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

В первом случае у нас имеется цельный алгоритм. Здесь применим подход черного ящика, который необходимо вскрыть, т.к. изменить нужно алгоритм внутри. В алгоритме нет строго выделения блоков по работе с данными, алгоритм в общем случае представлен монолитно.

В случае функционального подхода алгоритм представлен последовательностью вызовов функций. Само решение формируется путем преобразования входа в выход последовательно от первой до последней функций. Все промежуточные варианты данных на стыке функций по сути и являются точками встраивания для изменения конечного результата. В данном примере перед формированием областей табличного документа добавим вызов функции фильтрации Отобрать для непустых строк.

Функциональный стиль позволяет представлять цельный алгоритм в виде конвейера преобразований. При таком подходе модификация алгоритма заключается в добавлении в цепочку преобразований дополнительных функций. При этом место добавления диктуется не структурой алгоритма, а структурой данных на данном этапе при передаче данных от одной функции к другой.

Пример решения в функциональном стиле:

Функция ТекстВОбласть(Элемент, Параметры) Экспорт
    ИмяОбласти = Лев(Элемент, 2);
    Если Параметры.Области.Найти(ИмяОбласти) <> Неопределено Тогда
        Область = Параметры.ПолучитьОбласть(ИмяОбласти);
        Область.Параметры.Текст = Прав(Элемент, СтрДлина(Элемент) - 4);
    Иначе
        Область = Параметры.ПолучитьОбласть("Строка");
        Область.Параметры.Текст = Элемент;
    КонецЕсли;
    Возврат Область;
КонецФункции
	
Функция СформироватьОписание()
    ТабличныйДокумент = Новый ТабличныйДокумент;
    Текст = ПолучитьМакет("README").ПолучитьТекст();
    Макет = ПолучитьМакет("Макет");
    РаботаСМассивом.АТДМассив(СтрРазделить(Текст, Символы.ВК + Символы.ПС, Ложь))
        .Отобрать("НЕ ПустаяСтрока(Элемент)")
        .Отобразить("Контекст.ТекстВОбласть(Элемент, Параметры)", ЭтотОбъект, Макет)
        .Положить(Макет.ПолучитьОбласть("Разделитель"))
        .ДляКаждого("Контекст.Вывести(Элемент)", ТабличныйДокумент);
    Возврат ТабличныйДокумент; 
КонецФункции
 
 Текст описания
 
 Отчет

Мутации данных это всегда побочный результат работы грязных функций. В функциональной парадигме принято избегать мутаций. Чистые функции без побочных эффектов легко тестируются, могут безопасно использоваться при параллельных вычислениях. Обратной стороной медали являются менее эффективный расход ресурсов: избыточное использование памяти и снижение производительности. Однако последнее, как показывает общепризнанная практика, зачастую не является критичным, но это уже не является темой данной публикации.

Стоит заметить, что в некоторых случаях "побочный эффект" является и результатом работы функции. Но тут уж ничего не поделаешь: сложности тестирования и распараллеливания вам обеспечены :)

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

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

Для работы с объектной моделью абстрактного массива необходимо вызвать функцию общего модуля АТДМассив(). В качестве параметра инициализации модели можно передать любую коллекцию, поддерживающую метод обхода элементов ДляКаждого. Обычно абстрактные алгоритмы сразу можно применять к такой коллекции, за исключением метода Сортировать. Последнее связано с тем, что функция сортировки является мутирующей и непосредственно изменяет массив, а значит рассчитана на работу с типом данных Массив.

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

Коллекция может быть преобразована в массив также после использования одной из чистых абстрактных функций. Это возможно потому, что результатом абстрактной функции является массив. Исключением пожалуй здесь может быть функция Преобразовать (map), результатом которой может быть объект любого типа.

Абстрактные алгоритмы потому и являются абстрактными, что содержат лишь часть общего алгоритма и используют в своей работе алгоритмы переданных им в качестве параметров функций. Однако встроенный язык 1С не содержит такого типа данных как Функция!

Несмотря на отсутствие в языке 1С функций как типа некоторые объекты платформы используют в качестве параметров имя функции и переданный контекст исполнения. Так обратные вызовы в 1С реализованы через использование объекта Описание оповещения, в конструктор которого передаются имя функции и контекст. Дополнительно в функцию обратного вызова можно передать параметры.

В предлагаемом подходе в абстрактные алгоритмы передается не просто имя функции, а выражение для вычисления. Такой подход позволяет не ограничиваться определенным интерфейсом функции, а использовать в каждом случае свой, наиболее подходящий для решения в задаче. Кроме того, выражение может вовсе не содержать вызов функции! В последнем случае мы практически получаем вариант анонимной функции.

В следующем примере я постарался отразить возможные варианты использования модели по максимуму. Задача имеет практическое применение. Представленное решение естественно не единственное, но в данном исполнении хорошо иллюстрирует функциональный подход.

Пример взят из обработки формирования сценария выгрузки данных VanessaAutomation. Мне необходимо было сделать доработку для выделения в выгрузку объектов метаданных по определенной подсистеме, включая все подчиненные.

В демообработку я вынес алгоритм заполнения метаданных из обработки Ванессы. На форму добавил выбор подсистемы и команду "Выбрать метаданные по подсистеме".

На примере реализации команд "Заполнить подсистемы" и "Выбрать метаданные по подсистеме" я продемонстрирую использование абстрактных функций, функций первого порядка.

Начнем с простого примера реализации команды "Заполнить подсистемы". Всю реализацию я буду демонстрировать с использованием модели абстрактного массива, а значит все выполнение будет у меня в контексте сервера.

Итак задача: необходимо заполнить массив полных имен по всем подсистемам метаданных. Для этого вызовем конструктор абстрактного массива с параметром верхнего узла Метаданные.Подсистемы.

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

Еще одной особенностью переданной функции является то, что она содержит в себе рекурсию через собственное преобразование в абстрактном массиве.

Следующая наша функция - ДляКаждого. Здесь в качестве функции первого порядка использована анонимная функция выполняющая метод списка выбора Добавить() для каждого элемента абстрактного массива. Побочным результатом последнего вызова будет заполненный список подсистем для выбора.

Функция ДополнитьПодсистемыПоИмени(Элемент, Накопитель, Путь = "") Экспорт
    ТекущийПуть = Путь + "\" + Элемент.Имя;
    Накопитель.Положить(ТекущийПуть);
    Если Элемент.Подсистемы.Количество() = 0 Тогда
        Возврат Накопитель;
    КонецЕсли;
    Подсистемы = РаботаСМассивом.АТДМассив(Элемент.Подсистемы)
        .Преобразовать("Контекст.ДополнитьПодсистемыПоИмени(Элемент, Накопитель, Параметры)", РаботаСМассивом.АТДМассив(), ЭтотОбъект, ТекущийПуть)
	.ВМассив();
    Накопитель.ДополнитьМассив(Подсистемы);
    Возврат Накопитель;
КонецФункции

Процедура КомандаЗаполнитьПодсистемыНаСервере()
    СписокВыбора = Элементы.ВыбраннаяПодсистема.СписокВыбора;
    СписокВыбора.Очистить();
    РаботаСМассивом.АТДМассив(Метаданные.Подсистемы)
        .Преобразовать("Контекст.ДополнитьПодсистемыПоИмени(Элемент, Накопитель)", РаботаСМассивом.АТДМассив(), ЭтотОбъект)
        .ДляКаждого("Контекст.Добавить(Элемент)", СписокВыбора);
КонецПроцедуры

На этом заполнение списка подсистем завершено! Перейдем к следующей команде: "Выбрать объекты подсистемы"

Алгоритм команды условно поделен на три части: поиск подсистемы по полному имени, формирование списка объектов метаданных подсистемы и всех ей подчиненных, пометка выбора в дереве объектов метаданных. Рассмотрим их отдельно.

На входе у нас полный путь выбранной подсистемы. В конструктор абстрактного массива передадим массив составляющих пути. В следующей абстрактной функции Преобразовать передадим в качестве анонимной функции метод подсистемы Найти. На выходе преобразования будет объект метаданных Выбранная подсистема.

//  Поиск подсистемы по полному имени
ОбъектМетаданныхВыбраннаяПодсистема = РаботаСМассивом.АТДМассив(СтрРазделить(ВыбраннаяПодсистема, "\", Ложь))
    .Преобразовать("Накопитель.Подсистемы.Найти(Элемент)", Метаданные);

Следующим на очереди будет задача определить список имен объектов метаданных выбранной подсистемы, включая все подчиненные ей. Для этого создадим абстрактный массив с конструктором по умолчанию. Далее методом Положить() поместим в массив саму выбранную подсистему. Абстрактным методом Преобразовать последовательно сформируем вначале абстрактный массив с подчиненными подсистемами, затем преобразуем подсистемы в массив объектов метаданных этих подсистем. Последовательным вызовом абстрактного метода Отобразить вначале преобразуем массив объектов в массив структур {Тип, Имя}, а затем в массив наименований по шаблону "Тип.Имя" - теперь у нас сформирован полный список имен объектов метаданных по выбранной подсистеме, включая подчиненные ей.

Последнее преобразование можно было бы сделать и одно, однако во втором преобразовании используется внешний параметр по трансляции типа в английский эквивалент (TypeTranslation - это соответствие русского наименования типа объектов метаданных (Справочник, Константы и т.д.) в английский вариант).

//  Добавляет подсистемы рекурсивно
Функция ДополнитьПодсистемы(Элемент, Накопитель) Экспорт
	Накопитель.Положить(Элемент);
	Если Элемент.Подсистемы.Количество() = 0 Тогда
		Возврат Накопитель;
	КонецЕсли;
	Подсистемы = РаботаСМассивом.АТДМассив(Элемент.Подсистемы)
		.Преобразовать("Контекст.ДополнитьПодсистемы(Элемент, Накопитель)", РаботаСМассивом.АТДМассив(), ЭтотОбъект)
		.ВМассив();
	Накопитель.ДополнитьМассив(Подсистемы);
	Возврат Накопитель;
КонецФункции

//  Добавляет состав метаданных подсистемы
Функция ДополнитьСостав(Элемент, Накопитель) Экспорт
	Если Элемент.Состав.Количество() = 0 Тогда
		Возврат Накопитель;
	КонецЕсли;
	Накопитель.ДополнитьМассив(Элемент.Состав, Истина);
	Возврат Накопитель;
КонецФункции

//  Разбивает полное имя объекта метаданных
Функция РазделитьПолноеИмя(Элемент) Экспорт
	Состав = СтрРазделить(Элемент.ПолноеИмя(), ".");
	Возврат Новый Структура("Type, Name", Состав[0], Состав[1]);
КонецФункции

//  Формирование списка объектов метаданных по выбранной подсистеме
ОбъектыМетаданных = РаботаСМассивом.АТДМассив()
    .Положить(ОбъектМетаданныхВыбраннаяПодсистема)
    .Преобразовать("Контекст.ДополнитьПодсистемы(Элемент, Накопитель)", РаботаСМассивом.АТДМассив(), ЭтотОбъект)
    .Преобразовать("Контекст.ДополнитьСостав(Элемент, Накопитель)", РаботаСМассивом.АТДМассив(), ЭтотОбъект)
    .Отобразить("Контекст.РазделитьПолноеИмя(Элемент)", ЭтотОбъект)
    .Отобразить("СтрШаблон(""%1.%2"", Контекст[Элемент.Type], Элемент.Name)", TypeTranslatiton);

Когда мы получили массив объектов метаданных в формате "Тип.Имя" останется найти их по этому имени в дереве метаданных и поставить по ним пометку выбора.

Предварительно необходимо сбросить все пометки выбора. Для этого необходимо инициализировать массив строками верхнего уровня, которые соответствуют типам метаданных: Справочники, Документы и т.д. Следующим преобразованием получим абстрактный массив подчиненных строк, содержащих уже имена объектов метаданных в формате "Тип.Имя" и для них также сбросим пометку выбора.

И последнее. Сделаем отбор по условию вхождения в массив, полученный на предыдущем этапе формирования списка выбранных объектов. По отобранным строкам проставим признак выбора.

//  Добавляет только подчиненные строки дерева метаданных
Функция ДополнитьПодчиненныеСтроки(Элемент, Накопитель) Экспорт
	Строки = Элемент.ПолучитьЭлементы();
	Если Строки.Количество() = 0 Тогда
		Возврат Накопитель;
	КонецЕсли;
	Накопитель.ДополнитьМассив(Строки);
	Возврат Накопитель;
КонецФункции

//  Обработка дерева объектов метаданных: пометка объектов метаданных по выбранной подсистеме
РаботаСМассивом.АТДМассив(MetadataList.ПолучитьЭлементы())
    .ДляКаждого("Элемент.Use = Ложь")
    .Преобразовать("Контекст.ДополнитьПодчиненныеСтроки(Элемент, Накопитель)", РаботаСМассивом.АТДМассив(), ЭтотОбъект)
    .ДляКаждого("Элемент.Use = Ложь")
    .Отобрать("Контекст.Найти(Элемент.FullName) <> Неопределено", ОбъектыМетаданных.ВМассив())
    .ДляКаждого("Элемент.Use = Истина");

В своей статье я хотел продемонстрировать, что абстрактные типы в 1С все-таки возможны 😊 Решение еще пока молодое и свою полезность ему еще предстоит доказать. Надеюсь вам было интересно.

Решение доступно на github. Решение не зависит от БСП и является самодостаточным. Вариант поставки: конфигурация, расширение.

Объект метаданных

Контекст

Комментарий

ОбщийМодуль.РаботаСМассивом

Клиент, Сервер

Библиотека работы с абстрактным массивом

Обработка.АТДМассив

Клиент, Сервер

Реализует объектную модель абстрактного массива

ВнешняяОбработка.ДемоАТДМассив

 

Примеры

 

Обновление от 14.07.2021: добавлена поддержка работы модели в контексте Клиент

Теперь модель абстрактного массива доступна в любом контексте.
Конструктор модели перенесен в модуль РаботаСМассивом. Модуль Общий удален.
Убрана прямая доступность к элементам массива. Для установки элементов теперь можно использовать либо конструктор, либо оператор Установить(Коллекция).
Добавлены терминальные операторы ВМассив(), ВФиксированныйМассив().

Элементы.ДоговорКонтрагентов.СвязиПараметровВыбора = РаботаСМассивом.АТДМассив()
	.Положить(Новый СвязьПараметраВыбора("Отбор.Владелец", "Объект.Организация"))
	.ВФиксированныйМассив();

ДопустимыеТипы = Новый ОписаниеТипов(РаботаСМассивом.АТДМассив()
	.Положить(Тип("СправочникСсылка._ДемоНоменклатура"))
	.Положить(ОбщегоНазначения.ОписаниеТипаСтрока(20))
	.ВМассив());

Добавлены методы: СортироватьПо, ДополнитьМассив.

Следующий пример работает как на клиенте, так и на сервере:

Сотрудники = РаботаСМассивом.АТДМассив()
	.Положить(Новый Структура("Фамилия, Имя, Отчество", "Иванов", "Иван", "Иванович"))
	.Положить(Новый Структура("Фамилия, Имя, Отчество", "Иванов", "Иван", "Гермагенович"))
	.Положить(Новый Структура("Фамилия, Имя, Отчество", "Савельев", "Иван", "Иванович"))
	.Положить(Новый Структура("Фамилия, Имя, Отчество", "Андреев", "Иван", "Иванович"))
	.Положить(Новый Структура("Фамилия, Имя, Отчество", "Андреев", "Андрей", "Андреевич"));
Сотрудники.СортироватьПо("Фамилия, Имя, Отчество");
Сотрудники.ДляКаждого("Сообщить(СтрШаблон(""%1 %2 %3"", Элемент.Фамилия, Элемент.Имя, Элемент.Отчество))"); // [Андреев Андрей Андреевич, Андреев Иван Иванович, Иванов Иван Гермагенович, Иванов Иван Иванович, Савельев Иван Иванович]

Пример с БСП:

Файлы = Новый Массив;
РаботаСФайлами.ЗаполнитьПрисоединенныеФайлыКОбъекту(СсылкаНаДокумент, Файлы);
СсылкаНаПрисоединенныйФайл = РаботаСМассивом.АТДМассив(Файлы)
	.Отобрать("СтрНайти(Элемент.Наименование, ""#БДДС#"") > 0")
	.Отобрать("НЕ Элемент.ПометкаУдаления")
	.Взять();

 

Массив абстрактные типы данных функции первого класса

См. также

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

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

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

28.08.2023    9556    YA_418728146    6    

143

Печать непроведенных документов для УТ, КА, ERP. Настройка печати по пользователям, документам и печатным формам

Пакетная печать Печатные формы Адаптация типовых решений Универсальные функции Платформа 1С v8.3 1С:ERP Управление предприятием 2 1С:Управление торговлей 11 1С:Комплексная автоматизация 2.х Россия Абонемент ($m)

Расширение для программ 1С:Управление торговлей, 1С:Комплексная автоматизация, 1С:ERP, которое позволяет распечатывать печатные формы для непроведенных документов. Можно настроить, каким пользователям, какие конкретные формы документов разрешено печатать без проведения документа.

2 стартмани

22.08.2023    2294    28    progmaster    8    

3

Расширение: Быстрые отборы через буфер [Alt+C] Копировать список, [Alt+V] Вставить список, [Ctrl+C] Копировать из файлов

Инструментарий разработчика Универсальные функции Платформа 1С v8.3 Конфигурации 1cv8 1С:Розница 2 1С:ERP Управление предприятием 2 1С:Бухгалтерия 3.0 1С:Управление торговлей 11 1С:Комплексная автоматизация 2.х 1С:Зарплата и Управление Персоналом 3.x Абонемент ($m)

Копирует в буфер значения из списков, из ячеек отчетов, таблиц, настроек списков, других отборов и вставляет в выбранную настройку отбора. Работает с Объект не найден. Работает как в одной так и между разными базами 1С. Использует комбинации [Alt+C] Копировать список, [Alt+V] Вставить список. Также для копирования данных используется стандартная [Ctrl+C] (например из открытого xls, mxl, doc и т.п. файла скопировать список наименований)

1 стартмани

13.10.2022    16424    143    sapervodichka    112    

130

Система контроля ведения учета [БСП]

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

В данном материале рассмотрим типовой алгоритм подсистемы контроля учета БСП в конфигурациях на примерах.

18.07.2022    7388    quazare    8    

110

Хитрости СКД. Часть 3

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

Столкнулся с тем, что мне приходится писать гору отчетов. Во многих приходится использовать повторяющиеся приемы. Решил написать шпаргалку, которая, надеюсь пригодится не только мне. В этой статье: Объединение ячеек в отчете только на определенном уровне иерархии, Постобработка итогов в табличном документе, Скрытие колонок в зависимости от количества месяцев в периоде.

28.05.2022    9441    milkers    11    

94

Модули общего назначения - готовые полезные функции и процедуры конфигураций на БСП

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

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

25.04.2022    15413    quazare    11    

138

Несколько простых приемов для удобной работы в конфигураторе

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

Простая и удобная среда разработки 1С:Предприятия позволяет практически любому человеку начать работать под капотом 1С - в конфигураторе. Время идет, новички становятся программистами, специалистами, а об удобных приемах работы узнают годами, по ходу своего карьерного пути. А здорово было бы, если бы все знали удобные приемы в начале своего пути? Эти несколько приемов будут полезны новичкам, так как они затрагивают ту область работы, с которой приходится сталкиваться в начале карьеры.

12.11.2021    17674    acces969    95    

148
Комментарии
Подписаться на ответы Инфостарт бот Сортировка: Древо развёрнутое
Свернуть все
1. Darklight 32 07.07.21 13:56 Сейчас в теме
Категорически поддерживаю данную концепцию ведения разработки. Недавно на Инфостарт уже выкладывалинечто подобное. Вам бы скооперироваться вместе с AntonProgma - и пилить сообща единую концепцию в одном (но можно и в нескольких совместимых) решениях. За абстракциями и функциональным подходом - и настоящее, и будущее. Надеюсь когда-нибудь оно настанет официально и в 1С Предприятие.

Теперь несколько замечаний.
Статья очень бодро начиналась и её было легко читать, но очень быстро текст стал становиться плохо воспринимаемым, обильно насыщенным обволакивающими фразами практически не поясняющими суть процесса. Много смакуется под различным лингвистическим соусом одно и то же - но оно остаётся таким же обтекаемым и малопонятным. В начале много примеров. В середине их почти нет.

Теперь технические.

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

Для перебора элементов Вы выбрали "встроенную" переменную "Элемент" - не самое удачное имя. Оно занято в 1С Предприятие 8. Да, и вот, если взять Kotlin - то там используют "it" - более универсальное встроенное имя - не только для перебора последовательностей - а вообще - везде, где есть потребность в единственной контекстной переменной - это унифицирует код - делая его более строгим и универсально подходящим для разного использования.
Я согласен, что в переводе на русский "it" может быть и не так благозвучен "Оно", а слово "Элемент" боле понятное. Я бы выбрал "Он" (в отношении Объект, Параметр, Элемент) или "Этот". Но можно ещё подумать.
Кстати, английский дубликат тоже надо ввести на всякий случай.

"Накопитель" - это тоже встроенная переменная? Вы бы хотя бы рассказали про то как оно внутри устроено - хотя бы в общих чертах. Рассказали бы по встроенные переменные и их назначение. Про API вызова и особенности построения анонимных функций.

Цепочки соединённых функций (в стиле LINQ) у Вас как - сразу выполняются - т.е. тут нет генераторов и отложенных вычислений? Если да - то это плохо - так как на этом теряется большая часть смысла такого подхода и в неправильных руках он приведёт к серьёзном снижению производительности.

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

Вот этот код - просто вынос мозга - если цель была упростить написание и читабельность - то получился полный провал!
Общий.АТДМассив(MetadataList.ПолучитьЭлементы())
    .ДляКаждого("Элемент.Use = Ложь")
    .Преобразовать("Контекст.ДополнитьПодчиненныеСтроки(Элемент, Накопитель)", Общий.АТДМассив(), ЭтотОбъект)
    .ДляКаждого("Элемент.Use = Ложь")
    .Отобрать("Контекст.Найти(Элемент.FullName) <> Неопределено", ОбъектыМетаданных.Элементы)
    .ДляКаждого("Элемент.Use = Истина");

Ну никак я не могу понять - если нам просто надо пометить по выбранной подсистеме "Элемент.Use = Истина" - зачем помечаем два набора как "Элемент.Use = Ложь"? В тексте никаких пояснений.
Или это не действие - а отбор (что мне сначала и показалось) - очень трудно воспринимать такой API , тем более без пояснений (если ели понял - что тут идёт некое продолжение предыдущего примера заполнения, отбора и установки пометки "Элемент.Use = Истина".

Зачем Вы постоянно обращаетесь к функции БСП "ОбщегоНазначенияКлиентСервер.ДополнитьМассив" - раз уж ввели расширенный объект-массив - так и придерживались бы такой же концепции - добавили бы данный метод в него.
Аналогично - я бы туда и функцию "СтрРазделить"

Функция "Сортировки" всё-таки должна быть возвращать новый Массив - не ломайте привычный шаблон функционального стиля программирования. Затраты памяти смехотворны (ну только если в массиве не гигантские строки; а для очень больших исходных массивов - ну введите доп аргумент, который их просто будет очищать - коли не нужны).

Что возвращает "Общий.АТДМассив()" - это объект-обработка?
Если да - то как же поддержка на стороне клиента? Вот общий модуль "ОбщийМодуль.РаботаСМассивом" у Вас помечен как поддерживающий клиентский контекст.

Общие модули Вы назвали тоже очень плохо - во первых полностью в разнобой, во вторых слишком уж эгоистично с вероятностью нарваться на такие же в конфигурации, в третьих по сути без префиксов-окончаний.
Уж не говорю зачем надо было назвать конструктор "АТДМассив" а не просто "Массив" - если нужны оба метода то может лучше разнести их по разным API-общим модулям - имена которых должны быть более поясняющими и конкретизирующими - за что они отвечают. Вот я делаю такие "МассивМенеджер_ОДП", "СтруктураМенеджер_ОДП", "ФормаМенеджер_ОДП". А внутри уже функции, например "ВСтруктуру" (хотя, наверное надо было просто "Структура", но ещё думал так называть конструктор, боялся путаницы, как и думал делать ещё и парные варианты типа "ИзСтруктуры"), "Объединить", "Сериализовать", "Создать" (у меня нет расширенных объектов-обработок - пока не дошёл да этого - в силу ограничений платформы в управляемых формах)

Сквозной пример ясно совсем не удался!

Ещё. Вот почитайте комментарий - примите к сведенью, если хотите вывести обработку за пределы эко-среды серверного десктопа.


И ещё. Интересно как у Вас работает вот эта цепочка
ДопустимыеТипы = Новый ОписаниеТипов(Общий.АТДМассив()
	.Положить(Тип("СправочникСсылка._ДемоНоменклатура"))
	.Положить(ОбщегоНазначения.ОписаниеТипаСтрока(20)).Элементы);

Как передаётся квалификатор строки в ОписаниеТипов?


В общем. Идея концепции то правильная. Осталось только правильно её подать!
PowerBoy; nagimo; +2 Ответить
3. kalyaka 1069 07.07.21 19:24 Сейчас в теме
(1)
уже выкладывалинечто подобное
видел, решил написать пока тема горячая :)
Статья очень бодро начиналась и её было легко читать
первая часть была простой
но оно остаётся таким же обтекаемым и малопонятным
оставлено на обсуждение, если будет интерес. Заранее не угадаешь, пойдет тема или нет, поэтому тратить много усилий для разъяснений тоже накладно. И не понятно, что именно нужно разъяснить или возможно нужно другой вообще пример разобрать.
Не считаю хорошим дизайном передачу абстрактных функций просто как текст
согласен, это решение компромиссное в рамках возможностей языка 1С. Конечно можно было бы переусложнить, но тогда сложность восприятия кода сведет на нет преимущества. Например, в абстрактном массиве есть функция НайтиЭлемент и в следующем коде
//  Обработка дерева объектов метаданных: пометка объектов метаданных по выбранной подсистеме 
Общий.АТДМассив(MetadataList.ПолучитьЭлементы())     .ДляКаждого("Элемент.Use = Ложь")
     .Преобразовать("Контекст.ДополнитьПодчиненныеСтроки(Элемент, Накопитель)", Общий.АТДМассив(), ЭтотОбъект)
     .ДляКаждого("Элемент.Use = Ложь")
     .Отобрать("Контекст.Найти(Элемент.FullName) <> Неопределено", ОбъектыМетаданных.Элементы)
     .ДляКаждого("Элемент.Use = Истина");
примера у меня был соблазн использовать эту функцию. Однако в попытке выразить в виде текстового выражения вложенное выражение я запутался в кавычках :) и решил использовать метод Найти из контекста. Хотя у меня есть пример и удачного использования функции НайтиЭлемент, возможно я его приведу в следующих публикациях.
Для простых случаев передачу строки тоже можно оставить
да, пока остановимся на простом случае :)
переменную "Элемент"
- в каком контексте занято?
слово "Элемент" боле понятное
согласен
Кстати, английский дубликат тоже надо ввести на всякий случай
пока нет такой необходимости :) Хотя проект открыт и доступен на github - можно и форкнуть :)
"Накопитель" - это тоже встроенная переменная?
скажем так, это предопределенная переменная в контексте исполнения абстрактной функции Преобразовать.
хотя бы рассказали про то как оно внутри устроено
- так вот, смотрите исходники. Я там даже постарался описания для функций сделать.
Цепочки соединённых функций (в стиле LINQ)
не понял идею с отложенными вычислениями. Здесь главная фишка в том, что не нужно хранить контекст (массив элементов, над которым происходят преобразования). В контекст абстрактного массива можно добавить дополнительные настройки, но пока я не придумал какие :) Еще цепочки, на мой взгляд, смотрятся хорошо в коде. В принципе можно использовать и процедурный подход работы с абстрактным массивом:
Фрукты = СтрРазделить("вишня, арбузы, бананы", ", ", Ложь);
РаботаСМассивом.ДляКаждого(Фрукты, "Сообщить(Элемент)");// [вишня, арбузы, бананы]
РаботаСМассивом.Сортировать(Фрукты);
РаботаСМассивом.ДляКаждого(Фрукты, "Сообщить(Элемент)");// [арбузы, бананы, вишня]
РаботаСМассивом.Сортировать(Фрукты, "Сравнить(Б, А)");// обратный порядок
РаботаСМассивом.ДляКаждого(Фрукты, "Сообщить(Элемент)");// [вишня, бананы, арбузы]

не привели ни одного теста производительности и сравнения двух концепций между собой
и не собирался. Однажды я уже сделал такую ошибку и больше повторять ее не собираюсь :) Нет, в принципе конечно можно проводить такие исследования, но нужно понимать, что вы хотите определить. Вот ссылки по теме Продуманная оптимизация, Преждевременная оптимизация.
Вот этот код - просто вынос мозга
этот пример здесь сознательно приведен. Основная фишка этого кода в том, что он работает с деревом значений на форме. В первом операторе в массив помещается коллекция строк верхнего уровня (типы метаданных: Справочники, Документы и т.д.), в следующей функции для каждой строки проставляется значение выбора Ложь, далее строки верхнего уровня преобразуются в массив строк второго уровня, далее происходит сброс в Ложь пометки выбора для уже этих строк. Далее функция Отобрать формирует массив строк, имя в которых совпадает из переданного массива ОбъектыМетаданных. Ну и наконец по отобранным строкам проставляется пометка выбора Истина.
Зачем Вы постоянно обращаетесь к функции БСП
все что можно переиспользовать я стараюсь переиспользовать.
Функция "Сортировки" всё-таки должна быть возвращать новый Массив - не ломайте привычный шаблон
ну это в идеальном мире, а на практике стандартно в JS например это мутирующая функция. Впрочем здесь проблем не должно быть, т.к. для применения функции нужно получить вначале массив. Массив можно получить либо автоматически при использовании любой чистой функции, либо вызвать функцию Массив.
Что возвращает "Общий.АТДМассив()" - это объект-обработка?
это объектная обертка, да, это обработка. Можно использовать вызовы из модуля РаботаСМассивом без обертки (приводил пример в этом ответе выше).
Общие модули Вы назвали тоже очень плохо - во первых полностью в разнобой, во вторых слишком уж эгоистично с вероятностью нарваться на такие же в конфигурации, в третьих по сути без префиксов-окончаний
про разнобой поясните пожалуйста. Префиксы не люблю. Надеюсь либо кто-нибудь, либо уже я сам сделают компилятор по типу webpack, тогда можно будет упаковывать все модули в один вместе с зависимостями.
назвать конструктор "АТДМассив" а не просто "Массив"
- Массив - это зарезервированное слово, нельзя :)
Вот почитайте комментарий - примите к сведенью
по ссылке нельзя найти конкретный комментарий, переход в форум. Приведите, пожалуйста, цитату.
Интересно как у Вас работает вот эта цепочка

ДопустимыеТипы = Новый ОписаниеТипов(Общий.АТДМассив()
    .Положить(Тип("СправочникСсылка._ДемоНоменклатура"))
    .Положить(ОбщегоНазначения.ОписаниеТипаСтрока(20)).Элементы);

Общий.АТДМассив() - пустой конструктор абстрактного массива
.Положить(Тип("СправочникСсылка._ДемоНоменклатура") - добавляет в массив тип номенклатуры и возвращает ссылку на абстрактный массив
.Положить(ОбщегоНазначения.ОписаниеТипаСтрока(20)
- добавляет в массив тип строки с квалификатором длины и возвращает ссылку на абстрактный массив
.Элементы - прямое обращение к массиву в абстрактном массиве
4. Darklight 32 08.07.21 11:21 Сейчас в теме
(3)
оставлено на обсуждение, если будет интерес. Заранее не угадаешь, пойдёт тема или нет

Как тема преподносится - так она и идёт.

Сравните как осуждали прошлую тему от "AntonProgma" и Вашу, как ставили оценки. Там разжевали всё более понятно. Если статья написана плохо - её и читать то не будут, тем более вникать и обсуждать.
2/3 Вашей статьи написано очень мутно - и большинством было просто проигнорировано - даже оценки, в т.ч. отрицательные, народ не стал ставить - просто забил на тему. Да и ничего особо нового (по сравнению с работой "AntonProgma") Вы тут не предложили.


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

Текущая реализация лично мне не нравится. Причины - я обосновал в предыдущем комментарии. Если не реализовывать к упрощённой схеме более продвинутую - то так оно и останется - просто далее будет до нагружаться упрощённая - превращаясь в неудобного монстра - Вы уже это делаете, вводя доп управляющие аргументы в функции.

Однако в попытке выразить в виде текстового выражения вложенное выражение я запутался в кавычках :)

Идей, у меня, на эту тему много, например так

//Гдет-то в глобальном модуле
Функция ВК(Стр, Уровень=1) экспорт
     возврат СтроковыеФункцииКлиентСервер.ДополнитьСтроку("",Уровень,"""","Слева")+Стр+СтроковыеФункцииКлиентСервер.ДополнитьСтроку("",Уровень,"""","Справа")
КонецФункци

//Для вложений больше 2-го уровня нужны по две кавычки т.к. в внутри вызова выражения они будут внутри строрки
Функция ВК2(Стр, Уровень=1) экспорт
     возврат СтроковыеФункцииКлиентСервер.ДополнитьСтроку("",Уровень*2,"""","Слева")+Стр+СтроковыеФункцииКлиентСервер.ДополнитьСтроку("",Уровень*2,"""","Справа")
КонецФункци

АтдМассив.Отобрать(Контекст.НайтиЭлементы(Элемент.FullName).ДляКаждого("+ВК(Элемент.Use = Истина)+")"
Показать


Но вот сейчас бы прям сделал так - ввёл бы в строке абстракцию для вложенных кавычек - отдельно открывающую блок "{" и отдельно закрывающую блок выражения "}" тогда вложенные выражения были бы такими
АтдМассив.Отобрать("Контекст.НайтиЭлементы(Элемент.FullName).ДляКаждого({Элемент.Use = Истина})"

А в строке эти фигурные скобки бы перед выполнением преобразовывал бы к "".

Но это, не очень хороший дизайн. Лучше, конечно использовать комбинации функций
АтдМассив.Отобрать(Функ("Контекст.НайтиЭлементы(Элемент.FullName)").Далее(Функ("ДляКаждого(арг1).УстановитьАргумент("арг1", Функ("Элемент.Use = Истина"))))"


Что-то тоже не очень красиво - ну надо думать....
Может вот так бы получилось
Ф1 = Функ("Контекст.НайтиЭлементы(Элемент.FullName)").Комбайн().ДляКаждого().Аргумент(Функ("Элемент.Use = Истина"),1).Закончить();
АтдМассив.Отобрать(Ф1)"




"переменную "Элемент""
- в каком контексте занято?

В Клиентском, в обработчиках - но уже понял, что клиентский контекст Вы не поддерживаете.


"Цепочки соединённых функций (в стиле LINQ)"
не понял идею с отложенными вычислениями

Вы не знаете как устроен C# LINQ?
Отложенные вычисления - один из столпов современного функционального стиля программирования - реализация генераторов - когда алгоритм задаётся выражением - но он выполняется только, когда идёт вызов оператора фактического получения данных. То есть сначала строится дерево выражения - потом оно оптимизируется - потом по нему строится алгоритм выполнения, где ряд действий комбинируется, обычно чтобы минимизировать циклы по условно одинаковым выборкам, и только затеем исполняется.

не привели ни одного теста производительности и сравнения двух концепций между собой
и не собирался.

Простите. После этого интерес к Вашей публикации резко упал. Без оценки производительности - это просто минное поле через которое идти то и не очень то хотелось!

В первом операторе в массив помещается коллекция строк верхнего уровня (типы метаданных: Справочники, Документы и т.д.), в следующей функции для каждой строки проставляется значение выбора Ложь, далее строки верхнего уровня преобразуются в массив строк второго уровня, далее происходит сброс в Ложь пометки выбора для уже этих строк. Далее функция Отобрать формирует массив строк, имя в которых совпадает из переданного массива ОбъектыМетаданных. Ну и наконец по отобранным строкам проставляется пометка выбора Истина.

Ну никак не пойму - зачем вы "Ложь" устанавливаете?

все что можно переиспользовать я стараюсь переиспользовать

Ещё одна ложка дёгтя. Вы хотели созддать красивый удобный API - или к одному неудобному, не полноценному и жутко не стабильному API (БСП) решили добавить ещё один такой же - и предложить хаотично ими пользоваться - выискивая где что реализовано или не реализовано? Нее - это не интересно никому!

"Функция "Сортировки" всё-таки должна быть возвращать новый Массив - не ломайте привычный шаблон"
ну это в идеальном мире, а на практике стандартно в JS например это мутирующая функция.

Вы предлагаете функциональный подход - в чисто функциональном подходе это не мудрующая функция! Не ломайте шаблон восприятия!

Впрочем здесь проблем не должно быть, т.к. для применения функции нужно получить вначале массив. Массив можно получить либо автоматически при использовании любой чистой функции, либо вызвать функцию Массив.

Не понял. У Вас в статье функция "Сортировать()" вызывается у "АТДМассива"

Префиксы не люблю.

Без них тяжело в 1С. Хаотичные имена это плохо. В общем имя общего модуля "Общий" мне категорически не нравится.

- Массив - это зарезервированное слово, нельзя :)

"Массив" - это не зарезервированное слово. Это имя типа. И имена типов вполне могут сочетаться с именами других членов метаданных и модулей, в т.ч. с именами общих модулей и именами функций:

Функция Массив(Коллекция, Фикс=Ложь, Результат=неопределено, Позиция=0) экспорт
	Перечислитель = РаботаСКоллекциями_ОДП.ПолучитьПеречилитель(Коллекция);
	Если Перечислитель=неопределено Тогда
		Если Фикс Тогда
			возврат Новый ФиксированныйМассив(Новый Массив());
		Иначе
			возврат Новый Массив();
		КонецЕсли;
	КонецЕсли;
	Если Результат=неопределено Тогда
		Количество = РаботаСКоллекциями_ОДП.ПолучитьКоличество(Коллекция, Истина);
		Рез = Новый Массив(Количество);    
	Иначе
		Рез = Результат;
	КонецЕсли;
	Для каждого Элемент из Перечислитель Цикл
		Значение = РаботаСКоллекциями_ОДП.ПолучитьОдиночноеЗначение(Элемент, Коллекция);
		Рез[Позиция] = Значение;
		Позиция = Позиция + 1;

		Перечислитель = РаботаСКоллекциями_ОДП.ПолучитьПеречилитель(Элемент);
		Если Перечислитель <> неопределено Тогда
			Массив(Коллекция,, Рез, Позиция=0);
		КонецЕсли;
	КонецЦикла;
	
	Если Фикс Тогда
		возврат Новый ФиксированныйМассив(Рез);
	Иначе         
		возврат Рез;
	КонецЕсли;
КонецФункции
Показать


Функция находится в общем модуле "Массив" и вот так могут вызвать потом

М = Массив.Массив(СписокЗначений.Создать(1,2,3,4,5));
М2 = Новый Массив(5);



по ссылке нельзя найти конкретный комментарий, переход в форум. Приведите, пожалуйста, цитату.

Простите - не ту ссылку вставил - вот этот комментарий посмотрите

ДопустимыеТипы = Новый ОписаниеТипов(Общий.АТДМассив()
.Положить(Тип("СправочникСсылка._ДемоНоменклатура"))
.Положить(ОбщегоНазначения.ОписаниеТипаСтрока(20)).Элементы);


Сначала подумал, что я что-то не знаю - попробовал во так

М2 = Новый Массив(5);
М2[0] = Тип("Дата");
М2[1] = ОбщийМодуль1.ОписаниеТипаСтрока(10);
М2[2] = Новый ОписаниеТипов("Строка", , Новый КвалификаторыСтроки(20,ДопустимаяДлина.Фиксированная));
М2[3] = Новый ОписаниеТипов("Число", Новый КвалификаторыЧисла(10,0));
М2[4] = Новый ОписаниеТипов("Число", Новый КвалификаторыЧисла(5,5));
оп = Новый ОписаниеТипов(М2);
типы = оп.Типы();
Показать


В типах был один тип - "Дата", так что добавление в массив типов значения типа "ОписаниеТипов" для создания нового "ОписаниеТипов" НЕ РАБОТАЕТ, увы :-(
Или у Вас там что-то хитрее - просто - если вы преобразуете вызовом так что в ".Элементы" у Вас "ОписаниеТипов" - то сработает. Но это вряд ли же так
5. kalyaka 1069 08.07.21 13:18 Сейчас в теме
(4)
Идей, у меня, на эту тему много, например так
Вот бы Вы еще потратили время на проверку этих идей и выложили бы результаты в виде публикации :)
но уже понял, что клиентский контекст Вы не поддерживаете
поддерживаю, вы не внимательно читали мой предыдущий ответ.
Вы не знаете как устроен C# LINQ
знаю теоретический, практический я все-таки программирую на 1С. Про генераторы интересная тема, можно подумать.
Без оценки производительности - это просто минное поле
здесь я исхожу из того, что вопрос производительности всегда решается в конкретном контексте и ограничений, либо это вопрос связан с измерением количества операций и достижения результата за конечное их количество. Первое требует контекста, второе - зависит от конкретной реализации и уже не будет абстрактным.
Ну никак не пойму - зачем вы "Ложь" устанавливаете?
сбрасываю флаг выбора на форме.
Нее - это не интересно никому!
чего так сразу то за всех? :)
"Массив" - это не зарезервированное слово
ок, действительно можно. У меня где-то была ошибка и запомнилось, что нельзя. Ну и все-таки в текущем наименовании видно отличие от встроенного массива.
Простите - не ту ссылку вставил - вот этот комментарий посмотрите
ну это я видел. У меня везде Вычислить, кроме ДляКаждого - здесь я не придумал как это обойти, может вы подскажите? Хотя для именованных функций можно и Вычислить, а вот для произвольного кода - ничего не придумал. Может добавить ДляКаждогоВычислить для именованных, а для остальных оставить ДляКаждого?
".Элементы" у Вас "ОписаниеТипов" - то сработает. Но это вряд ли же так
именно так :)
11. Артано 762 09.07.21 16:39 Сейчас в теме
Вторая публикация с "супер крутым технологичным кодом, через функцию "Выполнить()". Да что за мода то такая вставлять костыли в 1с которые работают ОДНОЗНАЧНО хуже чем штатный код?

(1) С Darklight соглашусь частично. Концепция имеет право на жизнь, но это же просто откровенные костыли. Тут не то чтобы правильно подать, тут надо свою виртуальную машину делать надо, ну или хотя бы компилятор в байт-код, чтобы костылинг хотя бы по быстродействию не проседал. Делать код просто и абстрактно "красивым" считаю детской болезнью.
vano-ekt; rabid_otter; +2 Ответить
12. AntonProgma 46 09.07.21 16:55 Сейчас в теме
(11) вызов любой функции замедляет работу 1с. Но для выполнения похожих действий функции все равно пишутся. Для упрощения кода программы.

Фирма 1с сама использует и Выполнить и Вычислить. Нет никакого табу на это. Костыли - это каждый раз писать чуть-чуть другой код через копипаст.
Darklight; +1 Ответить
13. Артано 762 09.07.21 17:10 Сейчас в теме
(12) У функций динамической компиляции произвольного кода есть очень узкая и определенная ниша. Здесь же костыль на их базе позиционируется как универсальное решение, что не есть правда.

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

Из последних - есть такое https://infostart.ru/public/1421272.
Если погуглить, то можно найти примеры классов из разряда мелких, но полезных улучшизмов. И нет там никакой "Выполнить", чего вы в неё уцепились, не пойму.
14. AntonProgma 46 09.07.21 17:14 Сейчас в теме
(13) а вы не могли бы очертить границы использования функции Выполнить в 1с?
15. Артано 762 09.07.21 17:16 Сейчас в теме
(14) Эмм, разве не очевидно? Упрощение переопределения для разовых вызовов кода, где время на компиляцию кода, будет не так заметно на фоне того, что именно будет выполнять скомпилированный код. Наиболее характерный и чистый пример это подсистема печати в БСП-шных конфигурациях
16. AntonProgma 46 09.07.21 17:19 Сейчас в теме
(15) то есть, ограничения только с производительностью связаны? Если она не критична, то выполнять код можно?
17. Артано 762 09.07.21 17:20 Сейчас в теме
(16) Не только, но это уже обсасывали не раз и есть в документации по платформе. Например нужно предусмотреть защиту от инъекций кода.
18. AntonProgma 46 09.07.21 17:26 Сейчас в теме
(17) спасибо. Тогда я все учёл)
19. Артано 762 09.07.21 17:28 Сейчас в теме
(18) Тогда ждём продолжения. Без шуток, слежу с интересом за развитием идеи.
22. kalyaka 1069 09.07.21 22:07 Сейчас в теме
(17)
уже обсасывали не раз и есть в документации по платформе
Что ж, обратимся к документации. Единственная проблема с безопасностью может возникнуть, если код построен таким образом, что на клиенте формируется текст исполнения и передается на сервер для исполнения. Так действительно делать не нужно.
Если у вас есть другие кейсы с проблемой безопасности, приведите их пожалуйста.
21. kalyaka 1069 09.07.21 21:58 Сейчас в теме
(13)
Из последних - есть такое https://infostart.ru/public/1421272
В публикации по ссылке вообще закрытый коммерческий код, как он работает - это еще вопрос.
Если погуглить, то можно найти примеры классов из разряда мелких, но полезных улучшизмов
Вообще речь не про "мелких, но полезных улучшизмов", а про концепцию абстрактного массива.
46. Артано 762 11.07.21 06:43 Сейчас в теме
(21)
В публикации по ссылке вообще закрытый коммерческий код, как он работает - это еще вопрос.

думаю, что можно спросить у автора.
Вообще речь не про "мелких, но полезных улучшизмов", а про концепцию абстрактного массива.

Концепция абстрактного массива есть и была уже давно. Здесь же поправлю - речь про реализацию на базе 1с. И вот именно реализация костыльная. К претензии, как и к самому факту её реализовать претензий нет. Но к самой реализации, где код итератора пишется через "Выполнить", ну извините нет.
Вот еще пример нашел из более старого, но более элегантного решения на тему
https://infostart.ru/public/865839
49. kalyaka 1069 11.07.21 19:45 Сейчас в теме
(46) Действительно, интересная идея. Что-то типа делегата, который передается в абстрактный алгоритм и тогда не нужно использовать Выполнить. Однако здесь другая сторона медали - на каждый такой делегат потребуется создать собственную обработку, дать ей имя и добавить в конфигурацию. Т.е. на каждую комбинацию условия фильтра, предиката, функции сортировки потребуется собственная обработка реализующая конкретное поведение.

Что-то в этом есть, однако мне кажется пока не практичным. Может быть только для самых общих случаев.
54. AntonProgma 46 12.07.21 13:16 Сейчас в теме
(49) ну это же просто унификация перебора. Причём здесь анонимные функции, не известно. Но важно, что реализовано без Выполнить!
56. Darklight 32 14.07.21 11:39 Сейчас в теме
(13)Не совсем соглашусь, что очень узкая ниша. Типовой код 1С её как раз и используется как замену лямбда-функциям и анонимным функциям. А то что не так уж часто - ну они сами понимают, что костыли, но странно, что до сих пор в процедурном языке нет анонимных процедур, и ссылок на процедуры с типовой поддержкой! В турбо паскале 80-х годов даже были - а это был классический простой процедурный язык. Хм... ну ссылки точно были а анонимные функции - ну наверное позже появились!
Кстати, если забить на лямбды и анонимные функции - то применение "Выполнить/Вычислить/"ВыполнитьОповещение/ВыполнитьОбработку­Оповещения" только для вызова другой функции (т.е. по принципу делегирования вызова), размещённой в конфигурации или во внешней обработке - вполне себе нормальное использование - не шибко сгижающее проихводительность относительно простого вызова не локальной функции (т.е. с переключением контекста).
Анонимные и лямбда функции тоже можно было бы добавить - но тут уже для эффективности нужна компиляция - как статическая (т.е. нужен препроцессинг),так и возможна динамическая (путём генерации внешней обработки и её подключения к сеансу) - это всё конечно костыли - но что делать, если платформа не развивается, а мир не стоит на месте. Если всё это упаковать в крассивую библиотеку, которая будет это всё эффективно использовать - то это имеет права на жизнь, пусть и ограниченную.
Артано; AntonProgma; +2 Ответить
20. kalyaka 1069 09.07.21 21:53 Сейчас в теме
(11)
ОДНОЗНАЧНО хуже чем штатный код
штатный код не поддерживает функциональную парадигму. Про "хуже" вы скорее всего имели в виду производительность? Тогда ответ ищите в (5), статья не про производительность
2. bulpi 215 07.07.21 14:01 Сейчас в теме
Интересно, забавно, практически бесполезно.
user1058740; rabid_otter; DoctorRoza; PowerBoy; DrAku1a; DJ_Codebase; Yashazz; Altavista.roman; zqzq; vano-ekt; Alex17; TMV; BigB; +13 Ответить
6. AntonProgma 46 08.07.21 21:35 Сейчас в теме
(2) Почему же бесполезно? Я так понял, автор придумал, где применить.
7. AntonProgma 46 08.07.21 21:52 Сейчас в теме
Не думал, что так скоро смогу сам критиковать решение с анонимными функциями. Очень рад это сделать!

1. Всё-таки, вычисляемые выражения являются скорее не функциями, а вставками кода. Простое занудство с моей стороны.
2. Сортировку лучше делать над массивами индексов значений, а не над массивами значений. Так должно тратиться меньше системных ресурсов при перестановках.
3. Подумываю объединить функцию filter и map в одну. В Питоне есть очень удобная конструкция [v + 1 for v in arr if v > 5] - очень часто нужна. Возможно, ту да же запихнуть sort, чтобы коллекция накапливалась уже отсортированная.
4. Модуль Общий не нужен.
23. kalyaka 1069 09.07.21 22:13 Сейчас в теме
(7) 1. Ндя :)
2. Не знаю как это можно реализовать
3. Так это Преобразовать (reduce)!
4. Здесь он нужен для лаконичности. Сравните: АТДМассив = Обработки.АТДМассив.Создать(); или АТДМассив = Общий.АДТМассив();
28. AntonProgma 46 10.07.21 09:00 Сейчас в теме
(23)
2. У сортируемого массива есть индексы элементов.: 0, 1, 2. И эти индексы хранятся и переставляются во временном массиве, а сравнение идет по значениям, получаемым из сортируемого массива по индексу. То есть, в перестановках участвуют числа, которые являются ключом для получения значения.

3. Интересно. Я привык, что reduce возвращает одно значение (например, итого). И у вас используется Накопитель, видимо, для накопления результата. Я же думаю, не объединить ли map и filter в одну функцию с двумя входящими выражениями.

4. Мне интуитивно кажется, что API работы с абстрактными массивами должен включать и функцию Создать. Это по крайней мере легче ложится с в понятие модульности. АТДМассив = РаботаСМассивами.новыйАТДМассив(). Конечно, если нет какого-нибудь неочевидного клиент-серверного правила, запрещающего так делать.
8. sfaqer 09.07.21 01:53 Сейчас в теме
https://github.com/sfaqer/onec-fluent

Я просто оставлю это здесь
rabid_otter; Артано; user1211160; nixel; +4 Ответить
24. kalyaka 1069 09.07.21 22:15 Сейчас в теме
(8) это не на встроенном языке 1С. Не понятно для чего это здесь? Возможно имелось в виду сделать также на встроенном языке 1С?
27. sfaqer 10.07.21 03:31 Сейчас в теме
(24) ну т.е по ссылке репозиторий с выгруженной в файлы конфигурацией 1С, это не на встроенном языке?
29. kalyaka 1069 10.07.21 09:40 Сейчас в теме
(27) извините, вы так молча оставили ссылку, что я подумал что вы подсунули мне известную ссылку fluent. Судя по истории коммитов мы с вами сделали похожие решения в разницу пару дней (ок, вы раньше :))
31. sfaqer 10.07.21 13:22 Сейчас в теме
(29) Ну и оно работает все же не только с массивом, но и с ТЗ/ДФК и т.д только мап пока нет, их надо отдельно подумать. Но в целом это и есть известный fluent только допиленный по местам чтоб работало в 1С)
33. kalyaka 1069 10.07.21 13:47 Сейчас в теме
(31) ну с этим у меня тоже нет ограничений, главное чтобы коллекция поддерживала обход ДляКаждогоИз
34. sfaqer 10.07.21 14:11 Сейчас в теме
(33) ну тоже не совсем так, если например передано ТЗ и вызвана сортировка по умолчанию без предиката то он немного развалится
35. kalyaka 1069 10.07.21 14:15 Сейчас в теме
(34) я думаю реализовать выбор предиката по умолчанию в зависимости от типа первого элемента. Если это структурный объект, то реализовать универсальную функцию Сравнить по полям объекта, по-умолчанию сделать по всем полям из 1-го объекта.

Либо добавить функцию СортироватьПо и там выбирать предикат по-умолчанию для структурных объектов.
37. sfaqer 10.07.21 15:13 Сейчас в теме
(35) ну вот во флюенте (что для оскрипта что для 1С, в целом без разницы апи одинаковый) сделано как раз СортироватьПо
30. kalyaka 1069 10.07.21 09:47 Сейчас в теме
(8)
	#Если Клиент Тогда
		ПроцессорКоллекций = ПолучитьФорму("Обработка.ПроцессорКоллекций.Форма.Форма");
	#Иначе
		ПроцессорКоллекций = Обработки.ПроцессорКоллекций.Создать();
	#КонецЕсли
Классное решение! С ним текучий интерфейс доступен и на клиенте, замечательно!
32. sfaqer 10.07.21 13:23 Сейчас в теме
(30) Спасибо.) Да, создание формы это пожалуй единственный известный мне вариант создания собственного "класса" на клиенте
36. kalyaka 1069 10.07.21 14:42 Сейчас в теме
(8)интересное решение с терминальным оператором и отложенным вычислением. Типа возможно вычисление и не понадобится, но конвейер будет продекларирован? Или это сделано с заделом на оптимизацию конвейерных вычислений?

Еще одно замечание по поводу предиката, у вас я так понял для вычисления предиката используется Выполнить, и соответственно для него требуется не выражение, а код. Ну наверное это более универсальное решение, однако у Выполнить больше ограничений, чем у Вычислить. Например Выполнить не доступен на веб-клиенте.
38. sfaqer 10.07.21 15:20 Сейчас в теме
(36) разделение на конвейерные/терминальные операторы в целом обусловлено тем с чего черпалось вдохновение, а именно StreamAPI в java.
Ну и сделано в частности для того что по итогу конвейер может выработать не всю коллекцию, например после Первые(2) все методы будут вызвано соответсвенно только по 2 раза.
Ну и есть небольшой задел на будущее в части разделение на барьерные/не барьерные операции, т.е если в конвеере не встретится например сортировка, то не зависимо от количества операций весь конвеер можно пройти за один обход массива (возмонжо даже не полный).
Сейчас для простоты каждый этап конвеера барьерный (т.е должен обработать всю пришедшую коллекцию внутри себя, перед передачей в следующий этап), в будущем поведение изменится.
Ну и под оптимизации, например часть конвеерных методов может быть проигнорирована, в случае если терминальный метод например Количество() то условную сортировку можно проигнорировать так как она не повлияет на результат.
Такие размышления
41. kalyaka 1069 10.07.21 15:27 Сейчас в теме
(38)Замечательно! Приму на вооружение, спасибо за идею! :)
39. sfaqer 10.07.21 15:22 Сейчас в теме
(36) да, там Выполнить, сделано это в частности что бы на клиенте можно было принимать честный ОписаниеОповщения как предика, и апи при этом был одинаковый на сервере и на клиенте
40. kalyaka 1069 10.07.21 15:26 Сейчас в теме
(39) вот этот момент тоже поясните, пожалуйста. Зачем потребовалось использовать ОписаниеОповещения?
42. sfaqer 10.07.21 15:33 Сейчас в теме
(40) ну предположим у меня на клиенте есть процедура, которую я бы хотел использовать в качестве предиката для сортировки например, я создаю нативное описание оповещения, и передаю его в качестве предиката в конвейерный метод сортировать, тогда при сортировке, пол капотом будет выполнено нативное ВыполнитьОписаниеОповщения(), что в итоге не приведен к вызову Выполнить/Вычислить, что с одной стороны не потребует дополнителных динамических компиляций, с другой стороны более безопасно.
43. kalyaka 1069 10.07.21 15:41 Сейчас в теме
(42) Понятно! Есть конечно и плюсы, но и минусы :)

Диалог с вами получается самый продуктивный на форуме. Спасибо!
44. sfaqer 10.07.21 15:46 Сейчас в теме
(43) Ну, тут любое решение это компромис.)

Пожалуйста.)
9. Yashazz 4727 09.07.21 10:09 Сейчас в теме
После фразы "Список значений - узкоспециализированный тип под задачи преставления списков в интерфейсе." читать дальше не смог. Если автор в первых же строках несёт такую ахинею, то дальше читать как-то не хочется.
26. kalyaka 1069 09.07.21 22:32 Сейчас в теме
(9)
несёт такую ахинею
По всей видимости для вас Список значений - это абстрактный список, типа массива? Список значений появился еще в 1С 77 и там мог быть одновременно и визуализирован и использовался в коде. В 1С 8 список стал составной частью расширения элемента формы и утратил свою прямую визуализацию как элемент, однако у него сохранились методы по работе с интерфейсом: ВыбратьЭлемент, ОтметитьЭлементы + Метод формы ПоказатьВыборИзМеню - все эти методы ориентированы на структуру данных: Значение, Картинка, Пометка, Представление - такая структура говорит о специализации.
45. Yashazz 4727 10.07.21 22:30 Сейчас в теме
(26) Азы вы знаете, вижу. Но вы несколько упускаете из виду, что интерфейсная ипостась списка значений - не единственная и далеко не главная его возможность. Кстати, напомню, в 7.7 он мог работать почти эквивалентно нынешним структуре/соответствию.
Список значений, например, можно использовать как связный список, причём с сортировкой по обоим элементам кортежа, да ещё и с использованием бинарных флагов, да ещё с возможностью цеплять двоичные данные. Смотрите шире, интерфейсом мир не ограничивается)
Сам факт, что 1С сделала отдельную сериализацию списков, как бы намекает, что не совсем интерфейсный это объект)
It-developer; Артано; +2 Ответить
48. kalyaka 1069 11.07.21 19:40 Сейчас в теме
(45)ок, не совсем узкоспециализированный :))
10. DrAku1a 1718 09.07.21 13:40 Сейчас в теме
Ничего принципиально нового данные алгоритмы не делают. С другой стороны, код, написанный в одну строку плохо читается и отлаживается.
25. kalyaka 1069 09.07.21 22:19 Сейчас в теме
(10)
принципиально нового данные алгоритмы не делают
Согласен! Я здесь ничего и не придумывал и об этом прямо признался в статье.
С другой стороны, код, написанный в одну строку плохо читается и отлаживается.
Так не надо писать в одну строку. Или вы имеете в виду продолжение строки в текучем интерфейсе?
47. rabid_otter 134 11.07.21 11:23 Сейчас в теме
Очередные костыли на "выполнить" и "вычислить".
Без реализации средствами платформы - неотлаживаемый, потенциально опасный код без бизнесовой необходимости. Просто потому что захотелось анонимные функции в 1С?
Пишите в телеграмм, @platform_suggestions, может быть и внедрят в платформу, раз 1С идет по пути JS.
На инфостарте это бесполезная публикация, на вас выльют ушат помоев про "выполнить", а в платформе ничего не изменится и под каждым постом какой-нибудь упорный пионер 1С будет со всеми спорить.
so-quest; +1 Ответить
50. kalyaka 1069 11.07.21 19:53 Сейчас в теме
(47)
Очередные костыли
Похоже на заклинание :)
51. rabid_otter 134 11.07.21 20:26 Сейчас в теме
52. AntonProgma 46 12.07.21 10:27 Сейчас в теме
53. AntonProgma 46 12.07.21 12:01 Сейчас в теме
(52) единственная ассоциация такой фразы: js это электропоезд, а 1с идет по его путям)
55. starik-2005 3039 13.07.21 16:05 Сейчас в теме
Хороша статья. Не совсем ясно, за что влепили минусы. Автор, пеши есчо!
57. RustIG 1616 31.01.22 13:58 Сейчас в теме
Спасибо за статью!
с точки зрения математики (дисциплины Алгоритмы) и программирования сложных структур - отличная статья! чем больше людей будут описывать свое видение, получать фидбек - тем больше людей про это узнают, то-то поймут, что-то реализуют...

... про абстрактные типы еще писал RonX1 https://infostart.ru/profile/1207901/ - уже год как не заходит на портал ИС....
https://infostart.ru/1c/articles/1079893/

про односвязный список нашел вот тут - но скажу так, за 10 лет в 1с не сталкивался с задачами с применением односвязного списка...
https://www.youtube.com/watch?v=BK8-FydAQ-E&t=3348s
Оставьте свое сообщение