1

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?

Sandra Rossi
  • 11,934
  • 5
  • 22
  • 48
user9695260
  • 347
  • 3
  • 17
  • 1
    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 May 24 '19 at 20:26
  • Same question also asked on [SCN](https://answers.sap.com/questions/12695332/creating-a-range-for-a-field-from-internal-table-u.html) (no answer yet for now) – Sandra Rossi May 25 '19 at 07:34
  • @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 May 27 '19 at 09:21
  • @Florian there's no difference because there's no loop on components, only one component is checked for each row. – Sandra Rossi May 27 '19 at 15:52

3 Answers3

1

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.

Suncatcher
  • 10,355
  • 10
  • 52
  • 90
  • I wouldn't do the `CHECK sy-subrc` over and over again. It's sufficient to do this once for the whole table, not repeat it for every row. The component is either there in all rows or not. Also, ensure that `AND IS NOT INITIAL` is really intended - having an option `I EQ ` could actually be the desired behavior. – Florian May 27 '19 at 09:19
  • To be on the safe side, I suppose checking field symbol assignment each time is not bad, but I agree that it's redundant. Added it for conciseness of code, because checking before loop requires more lines of code. And I couldn't agree that adding multiple spaces to range table is a good idea, it could involve range bloating on bid datasets which is not good. OP can add single space to range if needed. – Suncatcher May 28 '19 at 08:31
0

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.

Florian
  • 4,821
  • 2
  • 19
  • 44
  • you assume the type of the component is char32? – Haojie May 27 '19 at 09:08
  • sadly cl_abap_corresponding does not support table_line. – Haojie May 27 '19 at 09:08
  • For the sample code, I simply assumed a type, yes. If the type is not known, this is not possible because the `narrow_table` cannot be declared in a static way. – Florian May 27 '19 at 09:15
  • `this variant turned out to be faster` what are your proofs? Did you conduct some benchmarking? – Suncatcher May 28 '19 at 08:25
  • These are the variants I used: https://github.com/HrFlorianHoffmann/AbapSamples/blob/master/ZCL_COMPARE_MAKE_RANGE_VARIANT.abap – Florian May 29 '19 at 07:47
0

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.
Haojie
  • 5,665
  • 1
  • 15
  • 14
  • Marco Polo?)) But I appreciate your code, it makes sense – Suncatcher May 28 '19 at 08:33
  • @Suncatcher I hope you understood what I meant. Macro is discouraged to use in most of modern programming languages. Of course you can discuss it. Just FYI . – Haojie May 28 '19 at 08:37
  • 1
    Agree, it is discouraged. But it makes code more concise and readable and is allowed in primitive one-liners (filling cells, structures, etc) where debugging is not critically needed – Suncatcher May 28 '19 at 10:07