Application Development Blog Posts
Learn and share on deeper, cross technology development topics such as integration and connectivity, automation, cloud extensibility, developing at scale, and security.
cancel
Showing results for 
Search instead for 
Did you mean: 
douglas_linkup
Explorer
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!
13 Comments
nomssi
Active Contributor
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
Hi Douglas,

 

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

 

regards,

Manish
douglas_linkup
Explorer
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
douglas_linkup
Explorer
0 Kudos
Hi Manish,

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

Regards,

Douglas
hana_admin
Discoverer
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

 
douglas_linkup
Explorer
0 Kudos
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.
Former Member
0 Kudos
Hello,

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

Regards,

Vikesh.
former_member184158
Active Contributor
0 Kudos

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

carlos_mayka
Explorer
0 Kudos
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.
sayan_banerjee
Explorer
0 Kudos
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

 
hagit
Active Participant
0 Kudos
Hello douglas.linkup

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
jens_seifert2
Explorer
0 Kudos
Hello,

your System has SP07 SP08 is needed.
hagit
Active Participant
0 Kudos
seifertj ,

Thank you for your reply.

Hagit

 

 
Labels in this area