Индексированная таблица значений - класс в составе 1С++, разработанный ADirks.

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

Документация по этому классу находится по ссылке.

Рассмотрим использование индексированной таблице на практических примерах.

Удобной оказывается группировка строк при создании документов, обработке данных, выводе отчетов и проч.

Например, мы хотим по данным, полученным из запроса, создать документы.

ИТЗ = СоздатьОбъект("ИндексированнаяТаблица");
RecordSet.ВыполнитьИнструкцию(ТекстЗапроса, ИТЗ, 1);
ИТЗ.Группировать("ИндДок:АдресДоставки","Количество",1);

В данном примере документы будут отличаться адресом доставки. Индекс можно делать и составным: "ИндДок:АдресДоставки,НомерЗаявки".

ИТЗ.ВыбратьСтроки();
Пока ИТЗ.ПолучитьСтроку() = 1 Цикл
    Док.Новый();
    //...
    ТЗТЧ = СоздатьОбъект("ТаблицаЗначений");

    ИТЗ.тзПотомки.Выгрузить(ТЗТЧ);

    Док.ЗагрузитьТабличнуюЧасть(ТЗТЧ);
    Док.Записать();
КонецЦикла;

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

Приведу еще один пример использования в типовых отчетах (конфигурация "Торговля и склад" и подобные ей) с группировками.

Процедура УстановитьГруппировкиЗапроса(ТекстЗагол)
    СписокГруппировок = СоздатьОбъект("СписокЗначений");
    СтрокаГруппировки = "";
    
    Для Сч = 1 По Группировки.РазмерСписка() Цикл
        Если Группировки.Пометка(Сч) = 1 Тогда
            ПредставлениеГрупп = "";
            ТекстГрупп = Группировки.ПолучитьЗначение(Сч, ПредставлениеГрупп);
            
            СтрокаГруппировки = СтрокаГруппировки + "Инд" + ТекстГрупп + ":" + ТекстГрупп + "; ";
            
            ТекстЗагол = ТекстЗагол + ?(ТекстЗагол = "", "", " / ") + ПредставлениеГрупп;
            СписокГруппировок.ДобавитьЗначение(ТекстГрупп, ПредставлениеГрупп);
        КонецЕсли;
    КонецЦикла;
    
    СтрокаГруппировки = Лев(СтрокаГруппировки, СтрДлина(СтрокаГруппировки) - 2);
КонецПроцедуры // УстановитьГруппировкиЗапроса()


Процедура ПечатьСтроки(ИТЗ, Ном, НазваниеСекции, ПечТекстСтроки, ТекРасшифровка = "")
    Если Ном = КоличествоГруппировок Тогда
        ПечПокупатель = Строка(ИТЗ.Покупатель) + РазделительСтрок + Строка(ИТЗ.Адрес);
        //... 
    Иначе
        ПечПокупатель = "";
        //...        
    КонецЕсли;    
        
    Таб.ВывестиСекцию(НазваниеСекции);
    глОживить(1);
КонецПроцедуры // ПечатьСтроки()


Процедура ВывестиГруппировку(ИТЗ, Ном)
    НазваниеГруппировки = СписокГруппировок.ПолучитьЗначение(Ном);    
    
    Если НазваниеГруппировки = "Документ" Тогда
        КолонкаСортировки = "День";
    Иначе
        КолонкаСортировки = НазваниеГруппировки;
    КонецЕсли;    
    
    ИТЗ.Сортировать(КолонкаСортировки);
    
    ИТЗ.ВыбратьСтроки();
    Пока ИТЗ.ПолучитьСтроку() = 1 Цикл
        ПечТекстСтроки = ИТЗ.ПолучитьЗначение(, НазваниеГруппировки);
        ТекРасшифровка = ПечТекстСтроки;
        
        Если НазваниеГруппировки = "Документ" Тогда
            НазваниеСекции = "Документ";
        Иначе    
            НазваниеСекции = "Строка" + Ном;
        КонецЕсли;    
                
        Если ПустоеЗначение(ПечТекстСтроки) = 1 Тогда
            ПечТекстСтроки = "Не выбран";
        КонецЕсли;
        
        ПечатьСтроки(ИТЗ, Ном, НазваниеСекции, ПечТекстСтроки, ТекРасшифровка);
        
        Если ИТЗ.НомерКолонки("тзПотомки") > 0 Тогда
            Если ПустоеЗначение(ИТЗ.тзПотомки) = 0 Тогда
                ВывестиГруппировку(ИТЗ.тзПотомки, Ном + 1);
            КонецЕсли;    
        КонецЕсли;
    КонецЦикла;
КонецПроцедуры // ВывестиГруппировку()

Использование в процедуре Сформировать():

СписокСортировки = "";
УстановитьГруппировкиЗапроса(ПечЗаголовокСтолбца);
КоличествоГруппировок = СписокГруппировок.РазмерСписка();

Состояние("Выполняется запрос...");

ИТЗ = СоздатьОбъект("ИндексированнаяТаблица");
RecordSet.ВыполнитьИнструкцию(ТекстЗапроса, ИТЗ);    

Состояние("Обработка данных...");

Если ПустаяСтрока(СтрокаГруппировки) = 0 Тогда
    ИТЗ.Группировать(СтрокаГруппировки, "Количество", 0);
КонецЕсли;

глЧислоСтрок = 0;

Таб.ВывестиСекцию("Кнопки");

//...

Если КоличествоГруппировок > 0 Тогда
    ВывестиГруппировку(ИТЗ, 1);
КонецЕсли;

ИТЗ.ЗаполнитьКолонку(, "День", 0);
ИТЗ.Свернуть("День", "Количество");
ИТЗ.ВыбратьСтроки();
ИТЗ.ПолучитьСтроку();

ПечатьСтроки(ИТЗ, 0, "Итого", "");  

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

Пример отчета с использованием ИТЗ.

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

ИТЗОстатков = СоздатьОбъект("ИндексированнаяТаблица");
RecordSet.ВыполнитьИнструкцию(ТекстЗапроса, ИТЗОстатков, 1);

ИТЗОстатков.ДобавитьИндекс("ИндТоварПартия", "Товар,Партия");

ТЗ.ВыбратьСтроки();
Пока ТЗ.ПолучитьСтроку() = 1 Цикл
    Спис = СоздатьОбъект("СписокЗначений");
    Спис.ДобавитьЗначение(ТЗ.Товар,   "Товар");
    Спис.ДобавитьЗначение(ТЗ.Партия,  "Партия");

    НомСтр = ИТЗОстатков.НайтиСтроку("ИндТоварПартия", Спис, , 1);
    Если НомСтр = 0 Тогда
        ТЗ.Количество = 0;
        Продолжить;
    КонецЕсли;
    
    Остаток = ИТЗОстатков.Остаток;
    СписатьКолво = Мин(Остаток, ТЗ.Количество);

    Если СписатьКолво = Остаток Тогда
        ИТЗОстатков.УдалитьСтроку(НомСтр);
    Иначе
        ИТЗОстатков.УстановитьЗначение(НомСтр, "Остаток", Остаток - СписатьКолво);
    КонецЕсли;

    ТЗ.Количество = СписатьКолво;
КонецЦикла;    

Пример поиска в индексированной таблице значений по одному значению. В данном примере находится строка в ИТЗ при переборе строк документа.

ИТЗОстатков = СоздатьОбъект("ИндексированнаяТаблица");
RecordSet.ВыполнитьИнструкцию(ТекстЗапроса, ИТЗОстатков, 1);

ИТЗОстатков.ДобавитьИндекс("ИндТовар", "Товар");

ВыбратьСтроки();
Пока ПолучитьСтроку() = 1 Цикл
    ТекТовар = Товар;

    НомСтр = ИТЗОстатков.НайтиСтроку("ИндТовар", ТекТовар, , 1);
    
    Если НомСтр = 0 Тогда
       Продолжить;
    КонецЕсли;

    Регистр.ЗаказыПоставщикам.Товар              = ИТЗОстатков.Товар;
    Регистр.ЗаказыПоставщикам.Поставщик          = ИТЗОстатков.Поставщик;
    Регистр.ЗаказыПоставщикам.ЗаказПоставщику    = ИТЗОстатков.ЗаказПоставщику;
    Регистр.ЗаказыПоставщикам.Количество         = Количество;
    Регистр.ЗаказыПоставщикам.Закрыт             = 0;
    Регистр.ЗаказыПоставщикам.КодОперации        = КодОперации;
    Регистр.ЗаказыПоставщикам.ДвижениеРасходВыполнить();
КонецЦикла;    

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

ИТЗ.ДобавитьИндекс("ИндТоварПоиск", "ТоварПоиск");

Затем создаем на форме текстовое поле "СтрПоиска" и прописываем обработку события для него. Не все строки попали в табличный документ, поэтому проверяем заполненность колонки "НомСтрТабл". В данном случае поиск будет осуществляться по первым символам поля "ТоварПоиск".

Процедура ВыполнитьПоиск()
    НомСтр = ИТЗ.НайтиБлижайшуюБольше(СокрЛП(Нрег(СтрПоиска)), "ИндТоварПоиск", 1);
    
    Если НомСтр = 0 Тогда
        Возврат;
    КонецЕсли;
    
    ТекСтрТабл = 0;
    
    Если ИТЗ.НомСтрТабл > 0 Тогда
        ТекСтрТабл = ИТЗ.НомСтрТабл;
    Иначе    
        Пока ИТЗ.СледующаяСтрока("ИндТоварПоиск", 0) = 1 Цикл
            Если ИТЗ.НомСтрТабл > 0 Тогда
                ТекСтрТабл = ИТЗ.НомСтрТабл;
                Прервать;
            КонецЕсли;    
        КонецЦикла;    
    КонецЕсли;
    
    Если ТекСтрТабл > 0 Тогда
        ТабЭлемент.УстановитьТекущуюЯчейку(ТекСтрТабл, 2);
    КонецЕсли;    
КонецПроцедуры // ВыполнитьПоиск()

 

Продолжение следует...