Modern Internal Table Operations
FILTER requires a sorted or hashed key (primary or secondary) on the filtered table (or the filter table):
11.1 VALUE
DATA(lt_orders) = VALUE tt_orders(
( order_id = '1' customer = 'C1' amount = 100 status = 'O' )
( order_id = '2' customer = 'C2' amount = 250 status = 'C' )
( order_id = '3' customer = 'C1' amount = 75 status = 'O' ) ).
" Default values for all rows
DATA(lt_open) = VALUE tt_orders( status = 'O'
( order_id = '4' customer = 'C3' amount = 10 )
( order_id = '5' customer = 'C3' amount = 20 ) ).
" Append to existing content
lt_orders = VALUE #( BASE lt_orders ( order_id = '6' customer = 'C4' amount = 5 ) ).
" Include lines of another table
lt_orders = VALUE #( BASE lt_orders ( LINES OF lt_open ) ).11.2 FOR iteration expressions
" Transform
TYPES tt_ids TYPE STANDARD TABLE OF ty_order-order_id WITH EMPTY KEY.
DATA(lt_ids) = VALUE tt_ids( FOR ls IN lt_orders ( ls-order_id ) ).
" Filter with WHERE
DATA(lt_c1) = VALUE tt_orders( FOR ls IN lt_orders WHERE ( customer = 'C1' ) ( ls ) ).
" With index and LET helper variables
DATA(lt_text) = VALUE string_table(
FOR ls IN lt_orders INDEX INTO lv_i
LET lv_prefix = |#{ lv_i }: | IN
( |{ lv_prefix }{ ls-customer } { ls-amount }| ) ).
" Nested FOR (cross product)
DATA(lt_pairs) = VALUE string_table(
FOR a IN lt_colors FOR b IN lt_sizes ( |{ a }-{ b }| ) ).
" Counter-based
DATA(lt_n) = VALUE int4_table( FOR i = 1 THEN i * 2 UNTIL i > 1000 ( i ) ).11.3 REDUCE
DATA(lv_total) = REDUCE decfloat34( INIT sum = CONV decfloat34( 0 )
FOR ls IN lt_orders
NEXT sum = sum + ls-amount ).
DATA(lv_open_count) = REDUCE i( INIT n = 0
FOR ls IN lt_orders WHERE ( status = 'O' )
NEXT n = n + 1 ).
DATA(lv_csv) = REDUCE string( INIT s = `` sep = ``
FOR ls IN lt_orders
NEXT s = s && sep && ls-order_id sep = `,` ).11.4 FILTER
FILTER requires a sorted or hashed key (primary or secondary) on the filtered table (or the filter table):
DATA lt_sorted TYPE SORTED TABLE OF ty_order WITH NON-UNIQUE KEY status.
lt_sorted = lt_orders.
DATA(lt_open2) = FILTER #( lt_sorted WHERE status = 'O' ).
DATA(lt_notopen) = FILTER #( lt_sorted EXCEPT WHERE status = 'O' ).
" Filter by another table
DATA lt_keep TYPE SORTED TABLE OF kunnr WITH UNIQUE KEY table_line.
lt_keep = VALUE #( ( 'C1' ) ( 'C3' ) ).
DATA(lt_sel) = FILTER #( lt_orders_by_cust IN lt_keep WHERE customer = table_line ).11.5 CORRESPONDING
There is also a lookup-table variant (CORRESPONDING #( itab FROM lookup_tab USING … )) that fills fields from a second table, and the class CL_ABAP_CORRESPONDING for mappings defined at runtime. Classic MOVE-CORRESPONDING a TO b. is still valid (also for tables since 7.40 SP05).
DATA ls_display TYPE zs_order_display.
ls_display = CORRESPONDING #( ls_order ). " same-named components
ls_display = CORRESPONDING #( ls_order MAPPING cust_no = customer EXCEPT status ).
ls_display = CORRESPONDING #( BASE ( ls_display ) ls_order ). " keep non-matched values
DATA(lt_disp) = CORRESPONDING tt_display( lt_orders ). " whole tables
lt_disp = CORRESPONDING #( lt_orders DISCARDING DUPLICATES ).11.6 Table comprehensions with conditions
DATA(lt_flagged) = VALUE tt_display(
FOR ls IN lt_orders
( order_id = ls-order_id
amount = ls-amount
flag = COND #( WHEN ls-amount > 200 THEN 'BIG' ELSE 'SMALL' ) ) ).11.7 GROUP BY loops (7.40 SP08+)
Unlike AT NEW, grouping does not require pre-sorting and works with any key expression.
" Group by customer and compute totals
LOOP AT lt_orders INTO DATA(ls_ord)
GROUP BY ( customer = ls_ord-customer
size = GROUP SIZE
index = GROUP INDEX )
ASCENDING
ASSIGNING FIELD-SYMBOL(<group>).
DATA(lv_sum) = REDUCE decfloat34( INIT s = CONV decfloat34( 0 )
FOR m IN GROUP <group> NEXT s = s + m-amount ).
out->write( |{ <group>-customer }: { <group>-size } orders, total { lv_sum }| ).
LOOP AT GROUP <group> INTO DATA(ls_member).
" each member row
ENDLOOP.
ENDLOOP.
" Groups as an expression
DATA(lt_customers) = VALUE string_table(
FOR GROUPS grp OF ls IN lt_orders GROUP BY ls-customer ( CONV string( grp ) ) ).11.8 Classic vs modern equivalents
READ TABLE t INTO w WITH KEY k = v. w = t[ k = v ]. READ … TRANSPORTING NO FIELDS + sy-subrc line_exists( t[ k = v ]) APPEND in loops VALUE #( ( …) ( …)) LOOP + APPEND VALUE #( FOR …) LOOP + ADD LOOP … WHERE + APPEND FILTER / VALUE #( FOR … WHERE …) CORRESPONDING #() SORT + AT NEW LOOP AT … GROUP BY
11.9 Performance notes
Use hashed tables (or sorted/secondary keys) for repeated key lookups; a linear READ inside a LOOP over a large table is O(n²).
Prefer ASSIGNING / REFERENCE INTO over INTO for wide rows or when modifying.
Avoid DELETE inside loops over the same table on large data; use DELETE … WHERE.
SORT once, then use BINARY SEARCH on standard tables if you can't change the type.