Массив структур 1С — массив, каждый элемент которого — структура с одинаковыми полями: Артикул, Количество, Цена. Это таблица без объекта «таблица»: элементы — строки, ключи — колонки. Его выбирают там, где таблица значений недоступна или мешает: в клиентском коде, при обмене между клиентом и сервером, в JSON. Ниже — создание, поиск, уникальность, группировка, сортировка через временную таблицу значений, передача на сервер и JSON. Основной код собран в два общих модуля.
Платформа 8.3; СтрРазделить и СтрСоединить требуют режима совместимости не ниже 8.3.6, объекты JSON — платформы 8.3.6 и новее.
ОбщегоНазначения.ТаблицаЗначенийВМассив, но её описание предупреждает: для таблиц с большим количеством строк она не рекомендуется.ПрочитатьJSON превращает массив объектов в массив структур, ЗаписатьJSON пишет его обратно.| Массив структур | Таблица значений | |
|---|---|---|
| Тонкий и веб-клиент | доступен | недоступна |
| Возврат с сервера на тонкий клиент | да, если значения полей передаются | нет, только через реквизит формы |
ПрочитатьJSON и ЗаписатьJSON | напрямую | через массив структур |
| Разный набор полей у элементов | допустим | колонки общие |
| Поиск, сортировка, свёртка | своим кодом, он ниже | НайтиСтроки, Сортировать, Свернуть |
| Типы колонок, параметр запроса | нет | есть |
Для запроса, сложной свёртки и вывода в таблицу формы удобнее таблица значений. Перенос массива структур в неё с типизацией колонок разобран в статье про массив в таблицу значений и здесь не повторяется.
Элементы добавляют методом Добавить(), структуру создают конструктором: ключи через запятую, затем значения. Правило одно — новая структура на каждый элемент. Структура, созданная до цикла, попадёт в массив несколько раз одним и тем же объектом, и все элементы покажут данные последней строки.
// Общий модуль или модуль обработки. Только Массив и Структура,
// поэтому код работает и на клиенте, и на сервере.
// Строки - коллекция с полями Артикул и Количество:
// табличная часть, таблица значений, массив структур.
Функция ПозицииИзСтрок(Строки) Экспорт
Позиции = Новый Массив;
Для Каждого СтрокаКоллекции Из Строки Цикл
// Новая структура на каждой итерации. Созданная один раз до цикла,
// она попала бы в массив много раз - одним и тем же объектом
Позиция = Новый Структура("Артикул, Количество");
ЗаполнитьЗначенияСвойств(Позиция, СтрокаКоллекции);
Позиции.Добавить(Позиция);
КонецЦикла;
Возврат Позиции;
КонецФункции
Функция ЗаказСПозициями() Экспорт
Позиции = Новый Массив;
Позиции.Добавить(Новый Структура("Артикул, Количество, Цена", "A-100", 2, 150));
Позиции.Добавить(Новый Структура("Артикул, Количество, Цена", "B-205", 1, 990));
Позиции.Добавить(Новый Структура("Артикул, Количество, Цена", "A-100", 3, 150));
// Значение структуры - массив: заказ хранит список позиций
Заказ = Новый Структура("Номер, Позиции, Сумма", "ЗК-0125", Позиции, 0);
// Переменная цикла указывает на ту же структуру, что лежит в массиве:
// новое поле появится у самого элемента
Для Каждого Позиция Из Заказ.Позиции Цикл
Позиция.Вставить("Сумма", Позиция.Количество * Позиция.Цена);
Заказ.Сумма = Заказ.Сумма + Позиция.Сумма;
КонецЦикла;
// Поле элемента: индекс массива, затем ключ структуры
Если Заказ.Позиции.Количество() > 0 Тогда
Заказ.Вставить("ПервыйАртикул", Заказ.Позиции[0].Артикул);
КонецЕсли;
Возврат Заказ;
КонецФункции
Поле структуры может хранить массив, а его элементы — снова структуры: так выглядят заказ с позициями и разобранный JSON. Обращение идёт по цепочке: Заказ.Позиции[0].Артикул. Перед обращением по индексу проверяйте Количество(), иначе пустой массив даст ошибку «Индекс находится за границами массива».
Деталь цикла в ЗаказСПозициями: в массиве простых значений присваивание переменной цикла элемент не меняет (см. статью про массив в 1С), а здесь переменная указывает на ту же структуру, что лежит в массиве, и Позиция.Вставить("Сумма", …) меняет сам элемент.
Массив.Найти() здесь бесполезен: структуры он сравнивает как объекты, а не по содержимому. Поиск, отбор, выгрузку поля, удаление повторов, группировку, свёртку и сортировку без сервера собирает общий модуль МассивСтруктурКлиентСервер с флажками «Клиент (управляемое приложение)», «Сервер» и «Внешнее соединение». Элементом массива может быть структура или соответствие.
// Общий модуль МассивСтруктурКлиентСервер
// Флажки: Клиент (управляемое приложение), Сервер, Внешнее соединение;
// для обычных форм - ещё Клиент (обычное приложение). Вызов сервера снят.
// Элемент массива - Структура или Соответствие.
// СтрРазделить: режим совместимости конфигурации не ниже 8.3.6.
#Область ПрограммныйИнтерфейс
// Значение поля элемента или Неопределено, если такого поля нет.
Функция ЗначениеПоля(Элемент, ИмяПоля) Экспорт
ТипЭлемента = ТипЗнч(Элемент);
Если ТипЭлемента = Тип("Соответствие") Или ТипЭлемента = Тип("ФиксированноеСоответствие") Тогда
Возврат Элемент.Получить(ИмяПоля);
КонецЕсли;
Значение = Неопределено;
Элемент.Свойство(ИмяПоля, Значение);
Возврат Значение;
КонецФункции
// Первый элемент, у которого поле равно значению, или Неопределено.
Функция НайтиПоПолю(Массив, ИмяПоля, Значение) Экспорт
Для Каждого Элемент Из Массив Цикл
Если ЗначениеПоля(Элемент, ИмяПоля) = Значение Тогда
Возврат Элемент;
КонецЕсли;
КонецЦикла;
Возврат Неопределено;
КонецФункции
// Все элементы, совпавшие со всеми полями отбора, - как НайтиСтроки у таблицы.
// Отбор - Структура, например Новый Структура("Склад, Оплачен", Склад, Истина).
Функция НайтиПоОтбору(Массив, Отбор) Экспорт
Результат = Новый Массив;
Для Каждого Элемент Из Массив Цикл
Подходит = Истина;
Для Каждого Условие Из Отбор Цикл
Если ЗначениеПоля(Элемент, Условие.Ключ) <> Условие.Значение Тогда
Подходит = Ложь;
Прервать;
КонецЕсли;
КонецЦикла;
Если Подходит Тогда
Результат.Добавить(Элемент);
КонецЕсли;
КонецЦикла;
Возврат Результат;
КонецФункции
// Соответствие "значение поля -> первый элемент" для многократного поиска.
Функция ИндексПоПолю(Массив, ИмяПоля) Экспорт
Индекс = Новый Соответствие;
Для Каждого Элемент Из Массив Цикл
Ключ = ЗначениеПоля(Элемент, ИмяПоля);
Если Индекс.Получить(Ключ) = Неопределено Тогда
Индекс.Вставить(Ключ, Элемент);
КонецЕсли;
КонецЦикла;
Возврат Индекс;
КонецФункции
// Значения поля массивом, как ВыгрузитьКолонку у таблицы значений.
Функция ВыгрузитьПоле(Массив, ИмяПоля, БезПовторов = Ложь) Экспорт
Результат = Новый Массив;
Встречались = Новый Соответствие;
Для Каждого Элемент Из Массив Цикл
Значение = ЗначениеПоля(Элемент, ИмяПоля);
Если БезПовторов Тогда
Если Встречались.Получить(Значение) <> Неопределено Тогда
Продолжить;
КонецЕсли;
Встречались.Вставить(Значение, Истина);
КонецЕсли;
Результат.Добавить(Значение);
КонецЦикла;
Возврат Результат;
КонецФункции
// Новый массив без повторов по полю: остаётся первый элемент с каждым значением.
Функция УникальныеПоПолю(Массив, ИмяПоля) Экспорт
Результат = Новый Массив;
Встречались = Новый Соответствие;
Для Каждого Элемент Из Массив Цикл
Ключ = ЗначениеПоля(Элемент, ИмяПоля);
Если Встречались.Получить(Ключ) = Неопределено Тогда
Встречались.Вставить(Ключ, Истина);
Результат.Добавить(Элемент);
КонецЕсли;
КонецЦикла;
Возврат Результат;
КонецФункции
// Соответствие "значение поля -> массив элементов с этим значением".
Функция Сгруппировать(Массив, ИмяПоля) Экспорт
Группы = Новый Соответствие;
Для Каждого Элемент Из Массив Цикл
Ключ = ЗначениеПоля(Элемент, ИмяПоля);
Группа = Группы.Получить(Ключ);
Если Группа = Неопределено Тогда
Группа = Новый Массив;
Группы.Вставить(Ключ, Группа);
КонецЕсли;
Группа.Добавить(Элемент);
КонецЦикла;
Возврат Группы;
КонецФункции
// Свёртка, как Свернуть у таблицы значений: новый массив структур с полями
// группировки и суммами. Группы - в порядке первого появления.
// Пример: Свернуть(Позиции, "Склад, Номенклатура", "Количество, Сумма").
Функция Свернуть(Массив, ПоляГруппировки, ПоляСуммирования = "") Экспорт
Группировки = ИменаПолей(ПоляГруппировки);
Суммируемые = ИменаПолей(ПоляСуммирования);
Если Группировки.Количество() = 0 Тогда
ВызватьИсключение "Свернуть: не заданы поля группировки";
КонецЕсли;
Последнее = Группировки.ВГраница();
Результат = Новый Массив;
Корень = Новый Соответствие;
Для Каждого Элемент Из Массив Цикл
// По вложенному соответствию на каждое поле группировки, кроме последнего
Узел = Корень;
Для Номер = 0 По Последнее - 1 Цикл
Ключ = ЗначениеПоля(Элемент, Группировки[Номер]);
Вложенный = Узел.Получить(Ключ);
Если Вложенный = Неопределено Тогда
Вложенный = Новый Соответствие;
Узел.Вставить(Ключ, Вложенный);
КонецЕсли;
Узел = Вложенный;
КонецЦикла;
// На последнем уровне лежит сама итоговая структура
Ключ = ЗначениеПоля(Элемент, Группировки[Последнее]);
Итог = Узел.Получить(Ключ);
Если Итог = Неопределено Тогда
Итог = Новый Структура;
Для Каждого ИмяПоля Из Группировки Цикл
Итог.Вставить(ИмяПоля, ЗначениеПоля(Элемент, ИмяПоля));
КонецЦикла;
Для Каждого ИмяПоля Из Суммируемые Цикл
Итог.Вставить(ИмяПоля, 0);
КонецЦикла;
Узел.Вставить(Ключ, Итог);
Результат.Добавить(Итог);
КонецЕсли;
Для Каждого ИмяПоля Из Суммируемые Цикл
Слагаемое = ЗначениеПоля(Элемент, ИмяПоля);
Если ТипЗнч(Слагаемое) = Тип("Число") Тогда
Итог[ИмяПоля] = Итог[ИмяПоля] + Слагаемое;
КонецЕсли;
КонецЦикла;
КонецЦикла;
Возврат Результат;
КонецФункции
// Сортировка вставками на месте, без вызова сервера. Устойчивая:
// элементы с равным значением поля сохраняют взаимный порядок.
// Значения поля - одного типа: Число, Строка или Дата. Для сотен элементов.
Процедура СортироватьПоПолю(Массив, ИмяПоля, ПоУбыванию = Ложь) Экспорт
Для Индекс = 1 По Массив.ВГраница() Цикл
Текущий = Массив[Индекс];
Значение = ЗначениеПоля(Текущий, ИмяПоля);
Позиция = Индекс - 1;
Пока Позиция >= 0 И СтоитПосле(ЗначениеПоля(Массив[Позиция], ИмяПоля), Значение, ПоУбыванию) Цикл
Массив[Позиция + 1] = Массив[Позиция];
Позиция = Позиция - 1;
КонецЦикла;
Массив[Позиция + 1] = Текущий;
КонецЦикла;
КонецПроцедуры
#КонецОбласти
#Область СлужебныеПроцедурыИФункции
// "Склад, Номенклатура" -> массив имён полей без пробелов.
Функция ИменаПолей(СписокПолей)
Имена = Новый Массив;
Для Каждого Имя Из СтрРазделить(СписокПолей, ",", Ложь) Цикл
Если Не ПустаяСтрока(Имя) Тогда
Имена.Добавить(СокрЛП(Имя));
КонецЕсли;
КонецЦикла;
Возврат Имена;
КонецФункции
Функция СтоитПосле(Левое, Правое, ПоУбыванию)
Если ПоУбыванию Тогда
Возврат Левое < Правое;
КонецЕсли;
Возврат Левое > Правое;
КонецФункции
#КонецОбласти
ЗначениеПоля читает поле через Свойство() или Получить(). Нет поля — вернётся Неопределено, а не ошибка «Поле объекта не обнаружено»: массивы из внешних систем часто «дырявые».НайтиПоПолю перебирает элементы. Для многократного поиска один раз постройте ИндексПоПолю: поиск по ключу соответствия идёт без перебора.НайтиПоОтбору повторяет НайтиСтроки таблицы значений: совпасть должны все поля отбора.УникальныеПоПолю оставляет первый элемент с каждым значением и сохраняет порядок. ВыгрузитьПоле с параметром БезПовторов даёт готовый массив для условия В (&Список).Сгруппировать возвращает соответствие «значение → массив элементов». Порядок групп не гарантирован; упорядоченный результат даёт Свернуть.Свернуть строит вложенные соответствия, по уровню на поле, поэтому ссылки и даты сравниваются как есть. При склейке ключа в строку две ссылки с одинаковым наименованием слились бы в одну. Нечисловые слагаемые, например null из JSON, пропускаются.СортироватьПоПолю — устойчивая сортировка вставками на месте. Операторы > и < требуют значений одного типа: Число, Строка или Дата. Время растёт квадратично, так что это вариант для сотен элементов на клиенте.В конфигурации на БСП поле на сервере выгружает и ОбщегоНазначения.ВыгрузитьКолонку(Массив, "Артикул", Истина): функция обходит любую коллекцию, третий параметр оставляет уникальные значения.
Сортировки по полю элемента у массива нет. На сервере надёжнее всего временная таблица значений: в неё кладут только поля сортировки и номер элемента, сортируют методом Сортировать и собирают новый массив из исходных структур. Порядок задаётся строкой, как у таблицы: "Дата Убыв, Сумма". Модуль серверный — МассивСтруктурСервер с флажками «Сервер» и «Внешнее соединение»; в него же положим функцию для результата запроса.
// Общий модуль МассивСтруктурСервер
// Флажки: Сервер, Внешнее соединение; Вызов сервера снят.
// Запроса и таблицы значений на тонком клиенте нет,
// поэтому эти функции - в серверном модуле.
// Результат запроса -> массив структур с ключами по колонкам запроса.
// В отличие от таблицы значений такой массив можно вернуть на клиент.
Функция ИзРезультатаЗапроса(РезультатЗапроса) Экспорт
Ключи = "";
Для Каждого Колонка Из РезультатЗапроса.Колонки Цикл
Ключи = Ключи + ?(Ключи = "", "", ",") + Колонка.Имя;
КонецЦикла;
Результат = Новый Массив;
Выборка = РезультатЗапроса.Выбрать();
Пока Выборка.Следующий() Цикл
Элемент = Новый Структура(Ключи);
ЗаполнитьЗначенияСвойств(Элемент, Выборка);
Результат.Добавить(Элемент);
КонецЦикла;
Возврат Результат;
КонецФункции
// Новый массив из тех же структур в порядке сортировки.
// Порядок - строка, как у ТаблицаЗначений.Сортировать: "Дата Убыв, Сумма".
// ПоСсылке - Истина: ссылки сравниваются по значению ссылки, быстро;
// Ложь: по представлению, за которым платформа обращается к базе.
Функция Отсортировать(Массив, Порядок, ПоСсылке = Ложь) Экспорт
// Колонки - только поля сортировки и номер элемента в исходном массиве
Таблица = Новый ТаблицаЗначений;
ПоляСортировки = Новый Массив;
Для Каждого Часть Из СтрРазделить(Порядок, ",", Ложь) Цикл
Слова = СтрРазделить(СокрЛП(Часть), " ", Ложь);
Если Слова.Количество() > 0 Тогда
ПоляСортировки.Добавить(Слова[0]);
Таблица.Колонки.Добавить(Слова[0]);
КонецЕсли;
КонецЦикла;
Если ПоляСортировки.Количество() = 0 Тогда
ВызватьИсключение "Отсортировать: не задан порядок";
КонецЕсли;
Таблица.Колонки.Добавить("НомерЭлемента");
Для НомерЭлемента = 0 По Массив.ВГраница() Цикл
СтрокаТаблицы = Таблица.Добавить();
СтрокаТаблицы.НомерЭлемента = НомерЭлемента;
Для Каждого ИмяПоля Из ПоляСортировки Цикл
СтрокаТаблицы[ИмяПоля] = МассивСтруктурКлиентСервер.ЗначениеПоля(Массив[НомерЭлемента], ИмяПоля);
КонецЦикла;
КонецЦикла;
// Номер элемента - последний ключ: равные элементы сохранят исходный порядок
Если ПоСсылке Тогда
Таблица.Сортировать(Порядок + ", НомерЭлемента", Новый СравнениеЗначений);
Иначе
Таблица.Сортировать(Порядок + ", НомерЭлемента");
КонецЕсли;
Результат = Новый Массив;
Для Каждого СтрокаТаблицы Из Таблица Цикл
Результат.Добавить(Массив[СтрокаТаблицы.НомерЭлемента]);
КонецЦикла;
Возврат Результат;
КонецФункции
ПоСсылке = Истина передаёт объект СравнениеЗначений: ссылки сравниваются по значению, быстро, но не по алфавиту. Для алфавита на большом массиве добавьте строковое поле с наименованием и сортируйте по нему.ИзРезультатаЗапроса сохранит порядок УПОРЯДОЧИТЬ ПО.Массив структур передаётся параметром серверной процедуры и возвращается на клиент, если передаются все значения внутри:
УникальныйИдентификатор, вложенные массивы, структуры, соответствия и списки значений;СправочникОбъект, ДокументОбъект, запрос и его результат, данные формы — например, строку табличной части.Одного неподходящего значения в любой структуре хватит, чтобы вызов завершился ошибкой. Типичный сценарий — команда формы документа обрабатывает выделенные строки табличной части «Товары». Внеконтекстная функция получает только параметры, поэтому нужные поля строк перекладывают в массив структур.
// Модуль формы документа с табличной частью Товары
// (Номенклатура, Количество, Сумма) и командой СводкаПоВыделенным.
&НаКлиенте
Процедура СводкаПоВыделенным(Команда)
// Только нужные поля выделенных строк - в массив структур
Позиции = Новый Массив;
Для Каждого Идентификатор Из Элементы.Товары.ВыделенныеСтроки Цикл
СтрокаТоваров = Объект.Товары.НайтиПоИдентификатору(Идентификатор);
Позиции.Добавить(Новый Структура("НомерСтроки, Номенклатура, Количество, Сумма",
СтрокаТоваров.НомерСтроки, СтрокаТоваров.Номенклатура,
СтрокаТоваров.Количество, СтрокаТоваров.Сумма));
КонецЦикла;
Если Позиции.Количество() = 0 Тогда
Возврат;
КонецЕсли;
// Повторы номенклатуры ищем на клиенте, без вызова сервера
Группы = МассивСтруктурКлиентСервер.Сгруппировать(Позиции, "Номенклатура");
Для Каждого Группа Из Группы Цикл
Если Группа.Значение.Количество() > 1 Тогда
НомераСтрок = Новый Массив;
Для Каждого Позиция Из Группа.Значение Цикл
НомераСтрок.Добавить(Формат(Позиция.НомерСтроки, "ЧГ=0"));
КонецЦикла;
Сообщить(Строка(Группа.Ключ) + " повторяется в строках " + СтрСоединить(НомераСтрок, ", "));
КонецЕсли;
КонецЦикла;
// Итоги с сортировкой по наименованию - один внеконтекстный вызов
Итоги = ИтогиПоНоменклатуре(Позиции);
Для Каждого Итог Из Итоги Цикл
Сообщить(Строка(Итог.Номенклатура) + ": " + Итог.Количество + " на сумму " + Итог.Сумма);
КонецЦикла;
КонецПроцедуры
&НаСервереБезКонтекста
Функция ИтогиПоНоменклатуре(Знач Позиции)
Итоги = МассивСтруктурКлиентСервер.Свернуть(Позиции, "Номенклатура", "Количество, Сумма");
// Без СравнениеЗначений ссылки сортируются по представлению (обычно это наименование)
Возврат МассивСтруктурСервер.Отсортировать(Итоги, "Номенклатура");
КонецФункции
&НаСервереБезКонтекста передаёт на сервер только массив; контекстный &НаСервере отправил бы ещё и данные формы.Знач массив после вызова вернулся бы с сервера на клиент — лишний трафик.ПрочитатьJSON возвращает JSON-массив объектов массивом структур, а со вторым параметром Истина — массивом соответствий. Ответ сервиса удобно нормализовать: читать в соответствия, потому что ключи JSON бывают любыми, переименовать поля и подставить умолчания, где поля нет или пришёл null. ЗаписатьJSON принимает такой массив напрямую, но ссылку и Null не запишет — их надо заменить. Функции добавьте в модуль МассивСтруктурСервер; даты, кодировки и ошибки разбора — в статье про JSON в 1С.
// Добавьте в общий модуль МассивСтруктурСервер. Платформа 8.3.6 и новее.
// JSON-массив объектов -> массив структур с одинаковым набором полей.
// Поля - Структура: ключ - имя поля в 1С, значение - значение по умолчанию
// на случай, если поля нет в объекте JSON или там null.
// ИменаВJSON - Соответствие: имя поля в 1С -> ключ в JSON, если они различаются.
Функция МассивСтруктурИзJSON(ТекстJSON, Поля, ИменаВJSON = Неопределено) Экспорт
Чтение = Новый ЧтениеJSON;
Чтение.УстановитьСтроку(ТекстJSON);
Данные = ПрочитатьJSON(Чтение, Истина); // в соответствия: годятся любые ключи
Чтение.Закрыть();
Если ТипЗнч(Данные) <> Тип("Массив") Тогда
ВызватьИсключение "Ожидался JSON-массив объектов";
КонецЕсли;
Результат = Новый Массив;
Для Каждого ОбъектJSON Из Данные Цикл
Если ТипЗнч(ОбъектJSON) <> Тип("Соответствие") Тогда
Продолжить; // элемент массива - не объект, а число или строка
КонецЕсли;
Элемент = Новый Структура;
Для Каждого Поле Из Поля Цикл
КлючJSON = Поле.Ключ;
Если ИменаВJSON <> Неопределено И ИменаВJSON.Получить(Поле.Ключ) <> Неопределено Тогда
КлючJSON = ИменаВJSON.Получить(Поле.Ключ);
КонецЕсли;
Значение = ОбъектJSON.Получить(КлючJSON); // нет ключа или null - Неопределено
Элемент.Вставить(Поле.Ключ, ?(Значение = Неопределено, Поле.Значение, Значение));
КонецЦикла;
Результат.Добавить(Элемент);
КонецЦикла;
Возврат Результат;
КонецФункции
// Массив структур -> компактная строка JSON.
Функция МассивСтруктурВJSON(Массив) Экспорт
Запись = Новый ЗаписьJSON;
Запись.УстановитьСтроку(Новый ПараметрыЗаписиJSON(ПереносСтрокJSON.Нет));
ЗаписатьJSON(Запись, ЗначениеДляJSON(Массив));
Возврат Запись.Закрыть();
КонецФункции
// Пример: позиции из ответа сервиса -> свёртка по артикулу -> JSON.
Функция ПримерОбменаJSON() Экспорт
ТекстJSON = "[{""sku"": ""A-100"", ""qty"": 2, ""price"": 150},
|{""sku"": ""B-205"", ""qty"": null},
|{""sku"": ""A-100"", ""qty"": 3, ""price"": 150}]";
Поля = Новый Структура("Артикул, Количество, Цена", "", 0, 0);
ИменаВJSON = Новый Соответствие;
ИменаВJSON.Вставить("Артикул", "sku");
ИменаВJSON.Вставить("Количество", "qty");
ИменаВJSON.Вставить("Цена", "price");
Позиции = МассивСтруктурИзJSON(ТекстJSON, Поля, ИменаВJSON);
// У B-205 Количество = 0 (пришёл null) и Цена = 0 (поля не было)
Итоги = МассивСтруктурКлиентСервер.Свернуть(Позиции, "Артикул", "Количество");
// Два объекта: A-100 с количеством 5 и B-205 с количеством 0
Возврат МассивСтруктурВJSON(Итоги);
КонецФункции
// Копия коллекции, которую примет ЗаписатьJSON: Null -> null,
// ссылки и уникальные идентификаторы -> строка, пустая ссылка -> null.
Функция ЗначениеДляJSON(Значение)
ТипЗначения = ТипЗнч(Значение);
Если ТипЗначения = Тип("Массив") Или ТипЗначения = Тип("ФиксированныйМассив") Тогда
Результат = Новый Массив;
Для Каждого Элемент Из Значение Цикл
Результат.Добавить(ЗначениеДляJSON(Элемент));
КонецЦикла;
Возврат Результат;
КонецЕсли;
Если ТипЗначения = Тип("Структура") Или ТипЗначения = Тип("ФиксированнаяСтруктура") Тогда
Результат = Новый Структура;
Для Каждого КлючИЗначение Из Значение Цикл
Результат.Вставить(КлючИЗначение.Ключ, ЗначениеДляJSON(КлючИЗначение.Значение));
КонецЦикла;
Возврат Результат;
КонецЕсли;
Если ТипЗначения = Тип("Соответствие") Или ТипЗначения = Тип("ФиксированноеСоответствие") Тогда
Результат = Новый Соответствие;
Для Каждого КлючИЗначение Из Значение Цикл
// Ключ объекта JSON - только строка
Ключ = КлючИЗначение.Ключ;
Если ТипЗнч(Ключ) <> Тип("Строка") Тогда
Ключ = XMLСтрока(Ключ);
КонецЕсли;
Результат.Вставить(Ключ, ЗначениеДляJSON(КлючИЗначение.Значение));
КонецЦикла;
Возврат Результат;
КонецЕсли;
Если Значение = Null Или Значение = Неопределено Тогда
Возврат Неопределено;
КонецЕсли;
Если ТипЗначения = Тип("Строка") Или ТипЗначения = Тип("Число")
Или ТипЗначения = Тип("Булево") Или ТипЗначения = Тип("Дата") Тогда
Возврат Значение;
КонецЕсли;
// Ссылки и УникальныйИдентификатор: у справочников и документов - GUID,
// у перечислений - имя значения; пустая ссылка - null
Если Не ЗначениеЗаполнено(Значение) Тогда
Возврат Неопределено;
КонецЕсли;
Возврат XMLСтрока(Значение);
КонецФункции
После нормализации у всех элементов одинаковые поля, и работают точка и свёртка. Ключи итогового JSON — имена полей структур: если сервис ждёт sku, так и называйте поле. Ссылки уходят строкой — GUID у справочников и документов, имя значения у перечислений. Обратно ссылку даёт метод менеджера: Справочники.Номенклатура.ПолучитьСсылку(Новый УникальныйИдентификатор(СтрокаGUID)).
Массив соответствий — тот же список, где каждая запись — соответствие. Он нужен, когда:
order-id, 2024, price.old. Структура на таком ключе даёт ошибку «Задано неправильное имя атрибута структуры», соответствие примет любую строку;"id" и "ID", соответствие различает;Элемент["discount"] для отсутствующего ключа вернёт Неопределено, а не ошибку.Плата — синтаксис: точка не работает, а код под структуры падает: Элемент.Свойство("sku") даёт «Метод объекта не обнаружен (Свойство)». Поэтому массив соответствий хорош как слой между JSON и кодом, а внутри конфигурации удобнее массив структур. Функции МассивСтруктурКлиентСервер принимают оба варианта, правила передачи между клиентом и сервером те же.
Свойство() или ЗначениеПоля, а ответ сервиса нормализуйте функцией МассивСтруктурИзJSON.&НаКлиенте. Перенесите вызов на сервер или используйте СортироватьПоПолю.СортироватьПоПолю встретила ссылку, Неопределено или смесь типов. Такие поля сортируйте на сервере функцией Отсортировать.Позиции.Найти(Новый Структура("Артикул", "A-100")) ищет тот же самый объект, а не такое же содержимое. Нужен НайтиПоПолю.Знач она обратно не возвращается. Возвращайте результат из функции.Серверной функцией Отсортировать: МассивСтруктурСервер.Отсортировать(Позиции, "Склад, Сумма Убыв"). Направление пишут после имени поля, как в методе Сортировать таблицы значений; без него сортировка идёт по возрастанию.
Из таблицы в массив — функцией БСП ОбщегоНазначения.ТаблицаЗначенийВМассив, а для данных из запроса — функцией ИзРезультатаЗапроса выше, без промежуточной таблицы. Обратное преобразование с типизацией колонок — в статье массив в таблицу значений.
Нет. Условие В (&Список) принимает массив простых значений или ссылок: выгрузите нужное поле функцией ВыгрузитьПоле. Если в запросе нужны несколько полей сразу, например артикул и количество для соединения с остатками, переложите массив в таблицу значений с типизированными колонками.
Цикл с Добавить() копирует только массив, структуры внутри остаются общими. Нужна рекурсивная копия: в БСП это ОбщегоНазначения.СкопироватьРекурсивно на сервере и ОбщегоНазначенияКлиент.СкопироватьРекурсивно на клиенте, без БСП — функция КопияКоллекции из статьи про структуру 1С.
Такой массив обычно лишь транспорт внутри большой задачи: загрузки из файла, обмена с внешним сервисом, обработки выделенных строк документа. Если нужна готовая обработка или отчёт, а не разбор коллекций, посмотрите услугу отчёты и обработки 1С или разместите задачу на площадке: оценка бесплатная, ответ в течение рабочего дня.
Станьте частью сообщества!
Войдите или зарегистрируйтесь, и вы сможете участвовать в обсуждениях.