1
votes

I want to create a function/custom class method that takes in 2 parameters:

1) IM_ITAB type ANY TABLE

2) IM_COMPONENT type STRING

and returns 1 parameter:

1) EX_RANGE type PIQ_SELOPT_T

So, algorithm is like this:

  • First of all, we check if the column with a component name at all exists
  • Then, we check that internal table is not empty.
  • Then, we loop through internal table assigning component and filling range table. Code is below.
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.

But I want to improve the method further. If the imported internal table has, let's say, 255 columns, then it will take longer to loop through such table. But I need only one column to compose the range.

So I want to get components of internal table, then choose only one component, create a new line type containing only that component, then create internal table with that line type and copy.

Here is the pseudo code corresponding to what I want to achieve:

append corresponding fields of im_itab into new_line_type_internal_table.

How can I "cut out" one component and create a new line type using RTTS?

3
Having 255 columns or even 1000 columns will have no impact on your algorithm because you use LOOP AT ... ASSIGNING (only using INTO would impact it). RTTS might improve the performance, but only when you use the ranges table, but probably the gain is very very low. So, is your question really about using RTTS, or do you have a performance problem, or another problem? - Sandra Rossi
Same question also asked on SCN (no answer yet for now) - Sandra Rossi
@Sandra, "Having 255 columns or even 1000 columns will have no impact on your algorithm" doesn't seem to be entirely correct. I assume that the ASSIGN COMPONENT [...] OF STRUCTURE [...] varies with the number of columns in the table. At least my variant below suggests that there is a difference. - Florian
@Florian there's no difference because there's no loop on components, only one component is checked for each row. - Sandra Rossi

3 Answers

1
votes

You are overcomplicating everything, you don't need RTTS for that.

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.

And yes, as Sandra said, you won't gain any performance with RTTS, just the opposite.

0
votes

Surprisingly, this variant turned out to be faster:

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 delegates to a kernel function for the structure-to-structure move, which apparently is faster than the ABAP-native ASSIGN COMPONENT [...] OF STRUCTURE [...] TO FIELD-SYMBOL [...]. The actual loop then seems to be faster because it uses fixed-name assignments.

Maybe somebody could verify.

0
votes

I would not go for a 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.