How to avoid nested looping over internal tables in ABAP?

1.2k Views Asked by At

Can you avoid the nested loop on these two internal tables?

DATA: t_fieldcat TYPE slis_fieldcat_alv,
      t_fcat TYPE kkblo_t_fieldcat.

LOOP AT T_FIELDCAT INTO LX_FIELDCAT.
    LOOP AT T_FCAT INTO LX_FCAT.
***If they have the same fieldname, the col_pos from FCAT will be passed to FIELDCAT.***
      IF LX_FIELDCAT-FIELDNAME = LX_FCAT-FIELDNAME.
        LX_FIELDCAT-COL_POS = LX_FCAT-COL_POS.
        APPEND lx_fieldcat TO t_fieldcat.
        CLEAR lx_fieldcat.
      ENDIF.
 ENDLOOP.
ENDLOOP.

I want to know if it is possible to assign the field COL_POS of the internal table T_FCAT to the field COL_POS of the internal table T_FIELDCAT without the nested looping.

3

There are 3 best solutions below

0
Herr Berthm On

Use could just use the read table statement.

read table t_fcat into lx_fcat with key fieldname = lx_fieldcat-fieldname.
if sy-subrc = 0.
  ...
endif.

But you're not passing the field col_pos to the other fieldcatalog. You're adding a new line to it which will probably run into an endless loop. I would assign a field-symbol in the first loop and write the col_pos into it:

data: t_fieldcat type table of slis_fieldcat_alv,
      t_fcat     type kkblo_t_fieldcat,
      lx_fcat    type kkblo_fieldcat.
field-symbols: <lx_fieldcat> type slis_fieldcat_alv.

loop at t_fieldcat assigning <lx_fieldcat>.
  read table t_fcat into lx_fcat with key fieldname = <lx_fieldcat>-fieldname.
  if sy-subrc = 0.
***If they have the same fieldname, the col_pos from FCAT will be passed to FIELDCAT.***
    <lx_fieldcat>-col_pos = lx_fcat-col_pos.
  endif.
endloop.
0
Frontmaniaac On

So the bad news is that I have not figured out a way to do this without two loops.

But the good news is that I have found out two other solutions for this.

  1. The first one being rather similar to your question, using field-symbols and a WHERE clause in the LOOP, which removes the IF condition, but works the same. For the VALUE syntax, I copy everything from the existing structure(row) using BASE, and change one of the fields using the value from the other table.

     DATA: t_fieldcat TYPE TABLE OF slis_fieldcat_alv,
           t_fcat     TYPE kkblo_t_fieldcat.
    
     LOOP AT t_fieldcat ASSIGNING FIELD-SYMBOL(<ls_fieldcat>).
       LOOP AT t_fcat ASSIGNING FIELD-SYMBOL(<ls_fcat>) 
         WHERE fieldname = <ls_fieldcat>-fieldname.
    
         <ls_fieldcat> = VALUE #( BASE <ls_fieldcat> 
                                ( col_pos = <ls_fcat>-col_pos ) ).      
    
       ENDLOOP.
     ENDLOOP.
    
  2. The second solutions is much shorter, but much more complex for someone who did not learn the new syntax, but when is the best time if not now! ;)

     DATA: t_fieldcat     TYPE TABLE OF slis_fieldcat_alv,
           t_fieldcat_new TYPE TABLE OF slis_fieldcat_alv,
           t_fcat         TYPE kkblo_t_fieldcat.
    
     t_fieldcat_new = VALUE #( FOR item IN t_fieldcat
                               FOR fcat IN t_fcat 
                               WHERE ( fieldname = item-fieldname )
                          ( VALUE #( BASE item col_pos = fcat-col_pos ) ) ).
    

This writes the records in a new table, using the FOR loop I move across all the records in t_fieldcat, and the same with the t_fcat. This is like using two LOOPs. And the VALUE BASE syntax is the same like in the first solution.

This syntax might of course not work on the older systems.

Happy coding!

0
AlexSchell On

To avoid two nested loops and therefore reduce the asymptomatic complexity from O(n2) to O(n) I would suggest to define a hashed table type with fieldname as a key for field catalog table lookups. They are optimized for access via the primary table key and attain a constant access time, irrespective of the number of lines.

We should also keep in mind that hash table requires additional memory and are based on distributed memory management, i. e. the data is not stored in order in the memory and the memory position of an entry is calculated using the hash algorithm on the basis of a unique key. So we would actully trade memory for speed.

We define the type:

TYPES: ty_t_fieldcat_hashed TYPE HASHED TABLE OF slis_fieldcat_alv
                            WITH UNIQUE KEY fieldname.

and use afterwards only one loop and a hash table for a lookup:

DATA: t_fieldcat     TYPE ty_t_fieldcat_hashed,
      t_fieldcat_new TYPE TABLE OF slis_fieldcat_alv,
      t_fcat         TYPE kkblo_t_fieldcat.
        ...


t_fieldcat_new = VALUE #( FOR fcat IN t_fcat
( LINES OF COND #( WHEN line_exists( t_fieldcat[ fieldname = fcat-fieldname ] ) 
  THEN VALUE #( 
    LET <fs_fieldcat> = t_fieldcat[ fieldname = fcat-fieldname ] IN 
    ( CORRESPONDING #( BASE ( <fs_fieldcat> ) fcat  ) ) ) 
) ) ).

The syntax in this case is even more concise, but it works.