Skip to Content
Author's profile photo Douglas Santos

Replace the LOOP for REDUCE operator

Calm! Don’t hit me. I exaggerated in the title, but it isn’t at all a lie. I don’t want to stay repeating Horst Keller, but some ABAPers still come to me: “I never had to use REDUCE…”

An expression with the REDUCE reduction operator creates a result of a specified data type using the type of one or more condition expressions.
A new and more performative way to not use LOOP AT NEW, for example ( ok ok .. is very old ).
With REDUCE it is possible to do a mathematical operation grouping by the items of a certain table for example. That is, instead of making a LOOP inside LOOP between two tables, you can use REDUCE to directly access the items you need to read. The reading is based on a table, so you can use the FILTER operator, for example, to generate the internal table with only the desired items. See the example below:

 

REPORT ysamplelkp_reduce.

*------------------------------------------------*
* PURPOSE: For each order item, calculate
* the total value from the KOMV table
* (Conditions) where:
* Condition PBXX = value X
* Condition RA01 = value Y
*
* TOTAL / ITEM (NETWR) = Sum PBXX + Sum RA01
*------------------------------------------------*

CLASS demo DEFINITION.
  PUBLIC SECTION.
    CLASS-METHODS main.
ENDCLASS.

CLASS demo IMPLEMENTATION.
  METHOD main.

    TYPES:
      BEGIN OF y_ekpo,
        ebeln TYPE ekpo-ebeln,
        ebelp TYPE ekpo-ebelp,
        netwr TYPE ekpo-netwr,
      END OF y_ekpo,
      yt_ekpo TYPE SORTED TABLE OF y_ekpo
              WITH UNIQUE KEY ebeln ebelp,

      BEGIN OF y_komv,
        knumv TYPE komv-knumv,
        kposn TYPE komv-kposn,
        kschl TYPE komv-kschl,
        kwert TYPE komv-kwert,
      END OF y_komv,
      yt_komv TYPE SORTED TABLE OF y_komv
              WITH NON-UNIQUE KEY knumv kposn kschl
              WITH NON-UNIQUE SORTED KEY key_kposn COMPONENTS kposn kschl.

    DATA it_ekpo  TYPE yt_ekpo.
    DATA it_komv  TYPE yt_komv.

    it_ekpo =
      VALUE #(
        ( ebeln = '0040000000' ebelp = '10'	 )
        ( ebeln = '0040000000' ebelp = '20'	 )
        ( ebeln = '0040000000' ebelp = '30'	 )
              ).

    it_komv =
      VALUE #(
        ( knumv = '0000000001' kposn = '10'	kschl = 'RA01' kwert = '10.00'  )
        ( knumv = '0000000001' kposn = '10'	kschl = 'PBXX' kwert = '350.00' )
        ( knumv = '0000000001' kposn = '20'	kschl = 'RA01' kwert = '2.00'   )
        ( knumv = '0000000001' kposn = '20'	kschl = 'RA01' kwert = '3.50'   )
        ( knumv = '0000000001' kposn = '20'	kschl = 'PBXX' kwert = '400.00' )
        ( knumv = '0000000001' kposn = '10'	kschl = 'RA01' kwert = '5.00'   )
        ( knumv = '0000000001' kposn = '10'	kschl = 'PBXX' kwert = '200.00' )
              ).
    DATA(out) = cl_demo_output=>new( )->write_data( it_ekpo ).

    out->write_data( it_komv ).

*------------------------------------------------*
* Using LOOP and Work area (on purpose)
*------------------------------------------------*
    DATA st_ekpo     LIKE LINE OF it_ekpo.
    DATA st_ekpox    LIKE LINE OF it_ekpo.
    DATA st_komv     LIKE LINE OF it_komv.

    LOOP AT it_ekpo
      INTO st_ekpo.

      st_ekpox = st_ekpo.

      AT NEW ebelp.

        LOOP AT it_komv
           INTO st_komv
          USING KEY key_kposn
          WHERE kposn EQ st_ekpox-ebelp.

          st_ekpo-netwr = st_ekpo-netwr + st_komv-kwert.

        ENDLOOP.

        MODIFY it_ekpo FROM st_ekpo TRANSPORTING netwr.

      ENDAT.

    ENDLOOP.

    out->write_text( 'Using LOOP and Work area:' ).

    out->write_data( it_ekpo ).

*------------------------------------------------*
* Using REDUCE ( It's beautiful! )
*------------------------------------------------*
    LOOP AT it_ekpo
      ASSIGNING FIELD-SYMBOL(<fs_ekpo>).
      <fs_ekpo>-netwr = REDUCE netwr( INIT val TYPE netwr
                                      FOR wa IN
                                      FILTER #( it_komv
                                                USING KEY key_kposn
                                                WHERE kposn EQ CONV #( <fs_ekpo>-ebelp ) )
                                      NEXT val = val + wa-kwert ).
    ENDLOOP.

    out->write_text( 'Using REDUCE:' ).

    out->write_data( it_ekpo )->display( ).


  ENDMETHOD.
ENDCLASS.

START-OF-SELECTION.
  demo=>main( ).

Giving…

REDUCE:

 

This is a simple example. Probably I can get the same result without using LOOP in any way ( it’s for you to think ). For me, it’s a very clean code. For more details, I recommend a read on at Help SAP for Iteration Expressions.

 

Hugs!

Assigned Tags

      13 Comments
      You must be Logged on to comment or reply to a post.
      Author's profile photo Jacques Nomssi Nzali
      Jacques Nomssi Nzali

      Hello Douglas,

      while checking your use case for REDUCE, I kept thinking AT NEW was to be replaced by GROUP BY, so I tried...

          LOOP AT it_komv ASSIGNING FIELD-SYMBOL(<ls_komv>)
            GROUP BY ( key  = <ls_komv>-kposn ) 
            ASSIGNING FIELD-SYMBOL(<group_key>).
      
            ASSIGN it_ekpo[ ebelp = CONV #( <group_key> ) ] 
              TO FIELD-SYMBOL(<ls_ekpo>).
            <ls_ekpo>-netwr = 0.
            LOOP AT GROUP <group_key> ASSIGNING FIELD-SYMBOL(<member>).
              ADD <member>-kwert TO <ls_ekpo>-netwr.
            ENDLOOP.
          ENDLOOP.

      and it actually passes the test.

      Why am I not using REDUCE more? Maybe because there are always alternatives and the result is not seem beautiful in my eyes. Look at this code

        METHOD fill.
      *   Parse call hierarchy, apply custom filters, fill collection of messages
          mi_collector = ii_collector.
          LOOP AT mo_atra->it_austab_hier REFERENCE INTO mr_src.
            CHECK new_record( ).
            put_caller( get_caller( ) ).
          ENDLOOP.
        ENDMETHOD.

      It has special routines in the LOOP to encapsulate side effects, it is my attempt to make it expression oriented. Now will I get any benefit form re-implementing the routines for the NEXT part of the REDUCE statement? I will have to try...

      regards,

      JNN

      Author's profile photo Douglas Santos
      Douglas Santos
      Blog Post Author

      Hi JNN,

      Currently, this is the beauty of ABAP. We can use the new syntax to write elegant code in many ways. I made a simple code to exemplify REDUCE.

      Now will I get any benefit form re-implementing the routines for the NEXT part of the REDUCE statement?

      I would say no. But it doesn't prevent new codes from being written like this. If ABAP evolves, we have to keep up.

       

      Thank you JNN, for your recognition and support.

      Regards

      Douglas

      Author's profile photo Manish Choudhary
      Manish Choudhary

      Hi Douglas,

       

      Works only if it_komv is sorted table. What is IT_komv is not  sorted table.

       

      regards,

      Manish

      Author's profile photo Douglas Santos
      Douglas Santos
      Blog Post Author

      Hi Manish,

      The IT_KOMV makes reference to the type: YT_KOMV TYPE SORTED TABLE OF Y_KOMV.

      Regards,

      Douglas

      Author's profile photo HANA Admin
      HANA Admin

      Hi Douglas,

       

      I copied you code and tried to activate it I am getting an error that FILTER ANY( )  is not any internal table.

      Can you please let me know the reason for this.

      Is the Filter constructor is returning an internal table ?

      And  also in the LOOP inside LOOP we are adding each Condition value(KWERT) in KOMV table to Net PO value(NETWR) in EKPO table

      st_ekpo-netwr st_ekpo-netwr + st_komv-kwert.

      but we are not adding in Reduce Constructor we are just adding to initial VAL and.

      val val + wa-kwert

      Can you please tell me the difference from where the calue of netwr value is added ?

       

      Thanks

      Pawan Akella

       

      Author's profile photo Douglas Santos
      Douglas Santos
      Blog Post Author

      Hi Pawan.

      tried to activate it I am getting an error

      What's your version of the SAP_ABA component? The new Filter operator came with ABAP News for 7.40, SP08.

      Is the Filter constructor is returning an internal table ?

      Yes.

      Can you please tell me the difference from where the calue of netwr value is added ?

      This section...

      (...) ( INIT val TYPE netwr
              FOR wa IN
              FILTER #( it_komv
                        USING KEY key_kposn
                        WHERE kposn EQ CONV #( <fs_ekpo>-ebelp ) )
                        NEXT val = val + wa-kwert ).

      ... the FILTER returned a internal table, like this (first round)...

      ...and the NEXT uses the WA for work area for each row in the table.

       

      Regards.

      Douglas.

      Author's profile photo Former Member
      Former Member

      Hello,

      For Error 'FILTER ANY( )  is not any internal table'. Replace '#' with table type, here it is YT_KOMV.

      Regards,

      Vikesh.

      Author's profile photo Ebrahim Hatem
      Ebrahim Hatem

      Hello

      I would like to add something also about for loop. We can use for loop instead of Loop at even if you have more than one loop by using Reduce for some operation like sum.

       

      DATA lt_tab1 TYPE STANDARD TABLE OF i WITH EMPTY KEY.
      DATA lt_tab2 TYPE STANDARD TABLE OF i WITH EMPTY KEY.
      
      lt_tab1 = VALUE #( FOR i = 0 THEN i + 1 UNTIL i > 10 ( i ) ).
      lt_tab2 = VALUE #( ( 1 )  ( 1 )  ( 1 )  ( 2 ) ( 2 ) ( 8 ) 
                         ( 3 )  ( 4 )  ( 5 )  ( 3 ) ( 3 ) ).
      " ABAP 740
      DATA(lv_sum) = REDUCE i(  INIT sum = 0 " local variable
      FOR wa1 IN   lt_tab1 " for 1
      FOR wa2 IN lt_tab2 WHERE ( table_line =  wa1 ) " for 2
      NEXT sum = sum + wa2 ). " do sum
      
      "Before:
      DATA lvsum TYPE i.
      LOOP AT lt_tab1 INTO DATA(w1).
      LOOP AT lt_tab2 INTO DATA(w2) WHERE table_line = w1.
        lvsum = lvsum + w2.
      ENDLOOP.
      ENDLOOP.

       

       

      Best regards

      Author's profile photo C M
      C M

      Hi Experts,

      Can you guys please provide an example in which you have two or more nested loops and filling a third internal table? I mean, how can I translate the following nested loop into ABAP 7.4 FOR Iteration Expression?

      LOOP AT it_tempo INTO <fs_tempo>.

      CLEAR wa_result.

      MOVE-CORRESPONDING <fs_tempo> TO wa_result.

      wa_result-pur_orders = wa-pur_orders.

      wa_result-unrestricted_stck = wa-unrestricted_stck.

      LOOP AT it_marc ASSIGNING <fs_marc> WHERE  matnr = <fs_tempo>-matnr AND

      werks = p_werks AND

      lvorm = space.

      wa_result-werks = <fs_marc>-werks.

      READ TABLE it_makt ASSIGNING <fs_makt> WITH KEY    matnr = <fs_tempo>-matnr

      spras = sy-langu.

      IF sy-subrc = 0.

      wa_result-maktx = <fs_makt>-maktx.

          ENDIF.

      READ TABLE it_t023t ASSIGNING <fs_t023t> WITH KEY  matkl = <fs_tempo>-matkl

      spras = sy-langu.

      IF sy-subrc = 0.

      wa_result-wgbez = <fs_tempo>-wgbez.

      ENDIF.

      LOOP AT it_eina ASSIGNING <fs_eina> WHERE   matnr = <fs_tempo>-matnr AND

      loekz = ' '.

      wa_result-lifnr = <fs-eina>-lifnr.

      LOOP AT it_eine ASSIGNING <fs_eine> WHERE infnr = <fs_eina>-infnr AND

      loekz = ' '.

      wa_result-netpr = <fs_eine>-netpr.

      IF <fs_eine>-peinh = 0.

      wa_result-peinh = 1.

      ELSE.

      wa_result-peinh = <fs_eine>-peinh.

      ENDIF.

      APPEND wa_result TO ti_result.

      ENDLOOP.

      CLEAR: wa_result-lifnr, wa_result-name1.

      ENDLOOP.

        ENDLOOP.

      ENDLOOP.

      ***********************************************

      I'll be thankful if you can help me out with this big issue I have.

      Carlos.

      Author's profile photo Sayan Banerjee
      Sayan Banerjee

      Hello,

      Thank you for sharing this valuable blog.

      I would like to know one thing related to this, when I am using same internal table then, I am getting BCD compute overflow as the output length of BSEG-WRBTR is 16(I am using WRBTR to reduce in same internal and sum up), so giving error when addition is more than 16 digits.

      Thanks,

      Sayan

       

      Author's profile photo Hagit Sammet
      Hagit Sammet

      Hello Douglas Santos

      Thank you for your blog.

       

      I tried to activate a program with a simple example of REDUCE but received error

      Field "REDUCE" is unknown. It is neither in one of the specified tables                      

      nor defined by a "DATA" statement. "DATA" statement.                

      The code is:

      cl_demo_output=>display(
      REDUCE  i( INIT s = 0
      FOR  i = 1 UNTIL i > 10
      NEXT s = s + i ) ).

      My version is:

      Could you please tell me what is the problem?

      Thank you in advanced

      Hagit

      Author's profile photo Jens Seifert
      Jens Seifert

      Hello,

      your System has SP07 SP08 is needed.

      Author's profile photo Hagit Sammet
      Hagit Sammet

      Jens Seifert ,

      Thank you for your reply.

      Hagit