Создание диапазона для поля из внутренней таблицы с использованием RTTS

Я хочу создать метод функции/пользовательского класса, который принимает 2 параметра:

1) IM_ITAB типа ЛЮБАЯ ТАБЛИЦА

2) IM_COMPONENT типа STRING

и возвращает 1 параметр:

1) EX_RANGE тип PIQ_SELOPT_T

Итак, алгоритм такой:

  • Первым делом проверяем, существует ли вообще колонка с именем компонента
  • Затем мы проверяем, что внутренняя таблица не пуста.
  • Затем мы прокручиваем внутреннюю таблицу, назначая компонент и заполняя таблицу диапазонов. Код ниже.
METHODS compose_range_from_itab
    IMPORTING 
      IM_ITAB      type ANY TABLE
      IM_COMPONENT type STRING
    EXPORTING
      EX_RANGE     type PIQ_SELOPT_T.
...
METHOD compose_range_from_itab.

  DATA: lo_obj   TYPE REF TO cl_abap_tabledescr,
        wa_range TYPE selopt,
        lt_range TYPE piq_selopt_t.

  FIELD-SYMBOLS: <fs_line> TYPE ANY,
                 <fs_component> TYPE ANY.

  lo_obj ?= cl_abap_typedescr=>describe_by_data( p_data = im_itab ).

  READ TABLE lo_obj->key TRANSPORTING NO FIELDS WITH KEY name = im_component.

  IF sy-subrc IS INITIAL.

    IF LINES( im_itab ) GT 0.

      LOOP AT im_itab ASSIGNING <fs_line>.

        ASSIGN COMPONENT im_component OF STRUCTURE <fs_line> TO <fs_component>.

        wa_range-sign = 'I'.
        wa_range-option = 'EQ'.
        wa_range-low = <fs_component>.

        APPEND wa_range TO lt_range.

      ENDLOOP.

      SORT lt_range BY low.
      DELETE ADJACENT DUPLICATES FROM lt_range COMPARING low.

      ex_range[] = lt_range[].

    ENDIF.

  ENDIF.

ENDMETHOD.

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

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

Вот псевдокод, соответствующий тому, чего я хочу достичь:

append corresponding fields of im_itab into new_line_type_internal_table.

Как я могу «вырезать» один компонент и создать новый тип линии с помощью RTTS?

Наличие 255 столбцов или даже 1000 столбцов не повлияет на ваш алгоритм, потому что вы используете LOOP AT ... ASSIGNING (на него повлияет только использование INTO). RTTS может улучшить производительность, но только при использовании таблицы диапазонов, но, вероятно, выигрыш будет очень низким. Итак, ваш вопрос действительно касается использования RTTS, или у вас есть проблема с производительностью или другая проблема?

Sandra Rossi 24.05.2019 22:26

Тот же вопрос также задавали на SCN (пока нет ответа)

Sandra Rossi 25.05.2019 09:34

@Sandra, «Наличие 255 столбцов или даже 1000 столбцов не повлияет на ваш алгоритм» кажется не совсем правильным. Я предполагаю, что ASSIGN COMPONENT [...] OF STRUCTURE [...] зависит от количества столбцов в таблице. По крайней мере, мой вариант ниже предполагает, что разница есть.

Florian 27.05.2019 11:21

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

Sandra Rossi 27.05.2019 17:52
В PHP
В PHP
В большой кодовой базе с множеством различных компонентов классы, функции и константы могут иметь одинаковые имена. Это может привести к путанице и...
Принцип подстановки Лискова
Принцип подстановки Лискова
Принцип подстановки Лискова (LSP) - это принцип объектно-ориентированного программирования, который гласит, что объекты суперкласса должны иметь...
1
4
6 753
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Ответ принят как подходящий

Вы все усложняете, для этого вам не нужен RTTS.

DEFINE make_range.
  ex_range = VALUE #( BASE ex_range ( sign = 'I' option = 'EQ' low = &1 ) ).
END-OF-DEFINITION.

LOOP AT im_itab ASSIGNING FIELD-SYMBOL(<fs_line>).
  ASSIGN COMPONENT im_component OF STRUCTURE <fs_line> TO FIELD-SYMBOL(<fs_field>).
  CHECK sy-subrc = 0 AND <fs_field> IS NOT INITIAL.
  make_range <fs_field>.
ENDLOOP.

И да, как сказала Сандра, с RTTS вы не получите никакой производительности, как раз наоборот.

Я бы не стал делать CHECK sy-subrc снова и снова. Достаточно сделать это один раз для всей таблицы, а не повторять для каждой строки. Компонент либо есть во всех строках, либо нет. Кроме того, убедитесь, что AND <fs_field> IS NOT INITIAL действительно предназначено — наличие опции I EQ <space> действительно может быть желаемым поведением.

Florian 27.05.2019 11:19

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

Suncatcher 28.05.2019 10:31

На удивление этот вариант оказался быстрее:

CLASS-METHODS make_range_variant_2
  IMPORTING
    sample        TYPE table_type
    column        TYPE string
  RETURNING
    VALUE(result) TYPE range_type.

METHOD make_range_variant_2.

  TYPES:
    BEGIN OF narrow_structure_type,
      content TYPE char32,
    END OF narrow_structure_type.

  TYPES narrow_table_type TYPE STANDARD TABLE OF narrow_structure_type WITH EMPTY KEY.

  DATA narrow_table TYPE narrow_table_type.

  DATA(mapping) =
    VALUE cl_abap_corresponding=>mapping_table_value(
      ( kind = cl_abap_corresponding=>mapping_component srcname = column dstname = 'CONTENT' ) ).

  DATA(mover) =
    cl_abap_corresponding=>create_with_value(
      source      = sample
      destination = narrow_table
      mapping     = mapping ).

  mover->execute(
    EXPORTING
      source      = sample
    CHANGING
      destination = narrow_table ).

  LOOP AT narrow_table ASSIGNING FIELD-SYMBOL(<row>).

    INSERT VALUE #(
        sign   = 'I'
        option = 'EQ'
        low    = <row>-content )
      INTO TABLE result.

  ENDLOOP.

ENDMETHOD.

CL_ABAP_CORRESPONDING делегирует функцию ядра для перехода от структуры к структуре, что, по-видимому, быстрее, чем родной ABAP ASSIGN COMPONENT [...] OF STRUCTURE [...] TO FIELD-SYMBOL [...]. Тогда фактический цикл кажется более быстрым, потому что он использует назначения с фиксированным именем.

Может быть, кто-нибудь сможет проверить.

вы предполагаете, что тип компонента char32?

Haojie 27.05.2019 11:08

к сожалению, cl_abap_corresponding не поддерживает table_line.

Haojie 27.05.2019 11:08

Для примера кода я просто предположил тип, да. Если тип неизвестен, это невозможно, потому что narrow_table нельзя объявить статически.

Florian 27.05.2019 11:15
this variant turned out to be faster какие у вас доказательства? Вы проводили какой-то бенчмаркинг?
Suncatcher 28.05.2019 10:25

Вот варианты, которые я использовал: github.com/HrFlorianHoffmann/AbapSamples/blob/master/…

Florian 29.05.2019 09:47

Я бы не пошел на Macro.

Data:
      lr_data type ref to data.

FIELD-SYMBOLS:
      <lv_component> TYPE any,
      <ls_data> TYPE any.

CREATE DATA lr_data LIKE LINE OF im_itab.
ASSIGN lr_data->* TO <ls_data>.

"Check whether im_component exists
ASSIGN COMPONENT im_component OF STRUCTURE <ls_data> TO <lv_component>.

CHECK sy-subrc EQ 0.

LOOP AT im_itab INTO <ls_data>.
  APPEND VALUE #( sign = 'I' option = 'EQ' low = <lv_component> ) TO ex_range.
ENDLOOP.

Марко Поло?)) Но я ценю ваш код, он имеет смысл

Suncatcher 28.05.2019 10:33

@Suncatcher Надеюсь, ты понял, что я имел в виду. Макро не рекомендуется использовать в большинстве современных языков программирования. Конечно, вы можете это обсудить. Просто к вашему сведению.

Haojie 28.05.2019 10:37

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

Suncatcher 28.05.2019 12:07

Другие вопросы по теме