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!

To report this post you need to login first.

6 Comments

You must be Logged on to comment or reply to a post.

  1. Jacques Nomssi

    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

    (4) 
    1. Douglas Santos 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

      (0) 
  2. 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_ekponetwr st_ekponetwr + st_komvkwert.

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

    val val + wakwert

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

     

    Thanks

    Pawan Akella

     

    (1) 
    1. Douglas Santos 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.

      (0) 

Leave a Reply