Имеется список значений с группами справочника Номенклатура - СпГруппТоваров.

```1c
    ВыбратьСтроки();
    Пока ПолучитьСтроку() = 1 Цикл
    Если СпГруппТоваров.Принадлежит(Товар) = 1 Тогда
    // Собственно вопрос: как узнать номер позиции в СпГруппТоваров где сработало Принадлежит()?
    КонецЕсли;
    КонецЦикла;
```

Штатно никак. Может кто-то знает способ через внешние компоненты?
---
Реализовано через так Слово "так" надо заменить на другое, из (24). ;-P

Потому что перебирать весь справочник для каждой строки ТЧ - г...внокод.

Первое, что просится - установить в справочнике СкидкиПоГруппамТоваров сортировку по реквизиту "Товар" и использовать НайтиПоРеквизиту().
---
НомерПозиции = СпГруппТоваров.НайтиЗначение(Товар);
---
Не сработает, т.к. в списке группы
---
какое количество уровней иерархии справочника ?
---
Кол-во уровней 10
---
в списке только группы?
---
Нет. Есть как группы, так и отдельные элементы. Но по элементам всё понятно. Там через НайтиЗначение() сработает.
---
лень писать весь код
Подскажу только как найти корневого родителя для группы

```1c
    Папа = Товар.Родитель;
    Пока ПустоеЗначение(Папа.Родитель) = 0 Цикл
    Папа = Папа.Родитель;
    КонецЦикла;
```
---
Что это дает? Родители данного элемента справочника (Товара из документа) мне не интересны.
---
Через переменную Ном, вы получаете номер строки документа. Мне он не интересен. Ну, звыняйте - телепалка с утра барахлит.
(12) Родители данного элемента справочника (Товара из документа) мне не интересны. Неужели? А в СпГруппТоваров что? Не родители?
---
это даёт всех родителей одной конкретной позиции. Подставляя родителя в СпГруппТоваров.НайтиЗначение( ... ) найдется и номер позиции.
---
Подскажу только как найти корневого родителя для группы Вангую: через десяток-другой сообщений автора выяснится, что в СпГруппТоваров есть как элементы, так и группы разных уровней.

Поэтому ваш код, безусловно, правильный, только надо (автору!) вставить в цикл поиск родителя текущего уровня.

Но это, опять-таки, телепатия, которая сегодня у меня сбоит. ;-)
---
Не важно есть ли там элементы. Важно, что там есть группы товаров.
Есть факт, что Товар из текущей строки документа Принадлежит() списку значений. В какой позиции Принадлежит()?
---
Вам уже все разжевали и в рот положили код написали. Проглотить самостоятельно сможете?
---
Место разжевывания?
---
Место разжевывания? Мнэээ... афедрон! Или чем вы там думаете при вашей постановке задачи незнакомым людям. :-P
---
А вас просят лезть в каждое узкое горлышко и вставлять свое "авторитетное" мнение? Нечего ответить - не отвечайте. А хамить не надо.
---
Ручками перебирай элементы списка и для каждого ПринадлежитГруппе или равен в зависимости от ЭтоГруппа.

По другому никак - твоя хотелка противоречит назначению оптимизации метода Принадлежит, там оно под капотом все за один запрос пытается выполнится, а тебе разные нужны.
---
Сейчас так и делается. Но! 8 номенклатурных позиций проходят эту проверку за от 5 до 20 секунд. В зависимости от вложенности по уровням. Вот и встал вопрос об оптимизации кода.
---
Может кто-то знает способ через внешние компоненты? А тупо создать переменную и инкрементировать ее в цикле - религия не позволяет?

```1c
    НомерПозиции = 0;
    Ном = 0;
    ВыбратьСтроки();
    Пока ПолучитьСтроку() = 1 Цикл
    Ном = Ном + 1;
    Если СпГруппТоваров.Принадлежит(Товар) = 1 Тогда
    // Собственно вопрос: как узнать номер позиции в СпГруппТоваров где сработало Принадлежит()?
    НомерПозиции = Ном;
    КонецЕсли;
    КонецЦикла;
```

Надеюсь. не оскорбил ваши религиозные чувства?
---
Ничуть. Через переменную Ном, вы получаете номер строки документа. Мне он не интересен.
---
Напишу чуть подробнее.

Например, в переменной СпГруппТоваров есть 3 значения.
1. Группа номенклатуры "Хлеб"
2. Группа номенклатуры "Стройматериалы"
3. Группа номенклатуры "Автозапчасти"

Выбираем строки документа.
В строке №1 документа в реквизите "Номенклатура" записан элемент справочника "Гвозди 2.5х50", который находится в группе "Гвозди строительные", которая находится в группе "Метизы", которая находится в группе "Стройматериалы".

СпГруппТоваров.Принадлежит(Товар) даст результат 1.
Но как мне узнать, что эта 1 (единица) из-за того, что гвозди сработали во второй позиции списка значений?
---
Папа = Товар.Родитель;
поз = СпГруппТоваров.НайтиЗначение(Папа);
Пока поз = 0 Цикл
   Папа = Папа.Родитель;
   поз = СпГруппТоваров.НайтиЗначение(Папа);
КонецЦикла;
Сообщить("Товар "+Товар +" найден в позиции "+поз+", по группе "+Папа);
---
Вот-вот, именно это я и имел в виду. Но надо пару строк в начало добавить - см. (10)
---
Тут тогда проще сделать так:
1) Выбрать значения из списка СпГруппТоваров
2) Для каждого значения применить Принадлежит() и, если 1, то вот оно
---
```1c
    ВыбратьСтроки();

    Пока ПолучитьСтроку() = 1 Цикл
    Если СпГруппТоваров.Принадлежит(Товар) = 1 Тогда
    Для Каждого ГруппаТоваров Из СпГруппТоваров Цикл
    Сч = 0;
    Если Товар.ПринадлежитЭлементу(ГруппаТоваров) Тогда
    Сообщение = Новый СообщениеПользователю;
    Сообщение.Текст = Сч;
    Сообщение.Сообщить();
    КонецЕсли;
    Сч = Сч+1;
    КонецЦикла;
    КонецЕсли;
    КонецЦикла;
```
---
Вы тут языки объединили, но принцип я понял. Так и сделано. Но в момент выполнения строки с кодом
```1c
    Если Товар.ПринадлежитГруппе(ГруппаТоваров) = 1 Тогда
```
 по замеру времени уходит от 5 до 20 секунд (в зависимости от уровня товара). Вот эту строку и пытаюсь оптимизировать.
---
возможно, надо посмотреть не на текущую реализацию, а на задачу - которая потребовала текущей реализации - под другим углом?
.
СЗ.НайтиЗначение - самый быстрый метод.
ю
может быть - окажется что притекущей реализации вариант в (15) для каждого товара из ТЧ суммарно окажется менее затратным чем Принадлежит и потом (15). По сути применение (15) полностью покрывает задачу "принадлежности" и СЗ.Принадлежит можно не использовать вообще.
---
может быть - окажется ...окажется, что в СпГруппТоваров есть и "Гвозди строительные", и "Метизы", и "Стройматериалы" (см.6).

И спрашивается - на какую из этих строк должен указать поиск "Гвозди 2.5х50" при таком ТЗ?
---
а хз.. это уже от частностей задачи зависит.
при применении (15) - укажет на БЛИЖАЙШУЮ родительскую группу (Гвозди строительные). Мне кажется это логичным в общем случае. В частном - хз что ТС надо...
---
Любое срабатывание Принадлежит(). Вот где сработало, ту позицию и надо.
---
О, или так.
Собака, съеденная Злопом =)
---
Давайте пойдем не от Списка значений, а от справочников.

Имеем:
1) Справочник Номенклатура
2) Справочник Контрагенты
Это всё типовое, для ТиС 9.2

Также имеем:
3) справочник СкидкиПоГруппамТоваров, подчиненный справочнику Контрагенты.
Реквизиты справочника:
Товар - справочник Номенклатура
ПроцОпт - Число.

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

Реализовано через так:

```1c
    ВыбратьСтроки();
    Пока ПолучитьСтроку() = 1 Цикл
    СкидкиПоГруппамТоваров.ВыбратьЭлементы();
    Пока СкидкиПоГруппамТоваров.ПолучитьЭлемент() = 1 Цикл
    Если Товар.ПринадлежитГруппе(СкидкиПоГруппамТоваров.Товар) = 1 Тогда
    ПроцентСкидки = СкидкиПоГруппамТоваров.ПроцОпт;
    Прервать;
    КонецЕсли;
    КонецЦикла;
    КонецЦикла;
```

И вот тут строка с кодом

```1c
    Если Товар.ПринадлежитГруппе(СкидкиПоГруппамТоваров.Товар) = 1 Тогда
```

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

Попытка закинуть все группы товаров и их скидок в Таблицу значений, а ту в Список значений привела меня в тупик. Как выйти на скидку из Списка значений?
Принадлежит() срабатывает быстро. Но в Списке значений нет скидок. А в Таблице значений только группы товаров. И как в ней найти ту самую строку?
---
Реализовано через так Слово "так" надо заменить на другое, из (24). ;-P

Потому что перебирать весь справочник для каждой строки ТЧ - г...внокод.

Первое, что просится - установить в справочнике СкидкиПоГруппамТоваров сортировку по реквизиту "Товар" и использовать НайтиПоРеквизиту().
---
Так там группы товаров. А ищем элемент.
---
В итоге так и сделал. Сортировку по реквизиту в справочнике установил. А далее в коде уже сделал цикл прохода по Родителям и поиск через НайтиПоРеквизиту()
---
Но в Списке значений нет скидок. М-да. Кто мешает в качестве представления записать строку из значения скидки?

А после нахождения значения - преобразовать ее в число?
---
Не мешает никто. НО! В списке значений содержатся группы справочника Номенклатура. А ищем элемент справочника.
---
Сообщение было скрыто модератором.
---
что мешает перебирать СЗ не через конструкцию Для Каждого, а через конструкцию Для НомерСписка = 0 Как минимум, версия платформы. ;-)
---
В списке значений содержатся группы справочника Номенклатура. А ищем элемент справочника. А что такое, по-вашему, родители элемента, нахождение цепочки которых вам продемонстрировали в (15)? Открою секрет: это и есть группы - сюрприз!

Пациент безнадежен...
---
Я не понимаю, почему при обсуждении какого-то кода, надо обязательно переходить на личности и оскорблять человека? Что это? Завышенное ЧСВ? Или просто характер говеный? Почему вы позволяете себе общаться со мной с высокомерием?
Как рассказывается в анекдоте: "Какой из тебя Наполеон? Ты - жалкий, презренный червь!".

Но идею вашу осознаю. О результатах замеров отпишусь.
---
Так, восьмерочники! Собрались! А то и так уже ниже плинтуса пал секам...
---
```1c
    ВыбратьСтроки();
    Пока ПолучитьСтроку() = 1 Цикл
    Если СпГруппТоваров.Принадлежит(Товар) = 1 Тогда
    // Собственно вопрос: как узнать номер позиции в СпГруппТоваров где сработало Принадлежит()?
    _Родитель=Товар;
    Пока ПустоеЗначение(_Родитель)=0 Цикл
    _Позиция=спГруппТоваров.НайтиЗначение(_Родитель);
    Если _Позиция>0 Тогда
    Сообщить(_Позиция);
    Прервать;
    КонецЕсли;
    _Родитель=_Родитель.Родитель;
    КонецЦикла;

    КонецЕсли;
    КонецЦикла;
```

Так тоже долго?
---
Да. Львиная доля времени (более 70%) уходит на выполнение строки
```1c
    Если СпГруппТоваров.Принадлежит(Товар) = 1 Тогда
```
---
условие
Если СпГруппТоваров.Принадлежит(Товар) = 1 Тогда
убрать вообще.
принадлежит или нет - станет известно в результате прохода цикла по родителям.
конкретный результат зависит от соотносшения числа элементов в ТЧ дока и в СЗ.
а то может в ТЧ = 500 строк, в СЗ - 2 значения - это будет "долго", если ТЧ =2 строки, СЗ = 500 значений - это будет "быстро"
---
Да, вся суть этой ветки в том, чтобы убрать код с Принадлежит()
---
"Сопли и вопли" (с)

No comments.
---
Решение:
1) установил в справочнике "СкидкиПоГруппамТоваров" сортировку по реквизиту "Товар".
2) В цикле проходим по Родителям товаров и ищем через НайтиПоРеквизиту().

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