通过 REDUCE 根据条件检查 itab 的所有行?
Checking all rows of itab against a condition via REDUCE?
为了检查内部table lt_itab
的所有条目是否满足条件COND,我想使用REDUCE语句。一旦发生违反 COND 的行,循环当然需要终止。下面的第二个代码块似乎可以工作,但在我看来像是对迭代索引的轻微滥用。 您是否知道 REDUCE 语法中的 better/more 透明解决方案? 是否可以使用迭代变量的结构(整数、布尔值)? INDEX INTO
选项似乎不适用于 REDUCE。与内核版本 753(或更低版本)的兼容性会很好。
这是我的最小可重现示例 (MRE),它仅在 lvr_flag_allowed = abap_false OR
被注释掉时通过语法检查(即 -> "lvr_flag_allowed = abap_false OR
):
DATA: lt_itab TYPE TABLE OF i,
rv_flag_allowed TYPE boole_d.
lt_itab = VALUE #( ( 2 ) ( 1 ) ( -1 ) ( 5 ) ).
IF lt_itab IS NOT INITIAL.
rv_flag_allowed = REDUCE #( INIT lvr_flag_allowed = abap_true
FOR lvf_idx = 1 UNTIL lvr_flag_allowed = abap_false OR
lvf_idx > lines( lt_itab )
NEXT lvr_flag_allowed = xsdbool( lt_itab[ lvf_idx ] < 0 ) ).
ENDIF.
RETURN.
目前它给出了这个语法检查消息(它的ID是MESSAGEG[M
):
The variable "LVR_FLAG_ALLOWED" cannot be used here.
您知道这不起作用的技术原因吗? SAP documentation on REDUCE - Reduction Operator 仅表示
Usually the expression expr (after THEN) and the termination condition log_exp (after UNTIL or WHILE) depend on the iteration variable var.
因此,在写下这些内容时,我想到了一个解决方法 MRE:
DATA: lt_itab TYPE TABLE OF i,
* rv_flag_allowed TYPE boole_d,
rv_last_index TYPE i.
lt_itab = VALUE #( ( 2 ) ( 1 ) ( -22 ) ( 5 ) ( 7 ) ( 4 ) ).
IF lt_itab IS NOT INITIAL.
rv_last_index = REDUCE #( INIT lvr_last_index = 0
FOR lvf_idx = 1 THEN COND #( WHEN lt_itab[ lvf_idx ] < 0
THEN 0
ELSE lvf_idx + 1 )
UNTIL lvf_idx = 0 OR
lvf_idx > lines( lt_itab )
NEXT lvr_last_index = lvr_last_index + 1 ).
ENDIF.
RETURN.
它“双重”使用迭代索引和 returns rv_last_index = 3
。我现在返回一个整数而不是布尔值,以便检查正确的中止结果。这对你来说正确吗?
非常感谢您的反馈和改进建议(超越经典 while/until 循环 ;-))!
我实际上想用 line_exists
表达这一点,但不幸的是 table expressions only support equality comparisons(不幸的是不是 <
):
" invalid syntax v
DATA(some_negative) = xsdbool( line_exists( values[ table_line < 0 ] ) ).
稍微冗长但有效的变体是使用 LOOP AT
和直接 EXIT.
(是的,这不是“现代语法”,尽管 IMO 仍然非常可读):
DATA(some_negative) = abap_false.
LOOP AT values WHERE table_line < 0 TRANSPORTING NO FIELDS.
some_negative = abap_true.
EXIT.
ENDLOOP.
我不认为 REDUCE 是完成这项工作的正确工具,因为它应该将 table 理解为一个值(在其他语言中也没有短路,例如 .reduce
在 JS 中,尽管他们有其他方法用于此目的,如 .some
和 .every
等)。如果 truthy 行的数量很少,不对它们进行短路可能是可以接受的 table,并且这个 REDUCE
语句至少不会通过额外的 WHERE ( ... )
clause:
DATA(some_negative) = REDUCE abap_bool(
INIT result = abap_false
FOR entry IN values
WHERE ( table_line < 0 )
NEXT result = abap_true
).
为了检查内部table lt_itab
的所有条目是否满足条件COND,我想使用REDUCE语句。一旦发生违反 COND 的行,循环当然需要终止。下面的第二个代码块似乎可以工作,但在我看来像是对迭代索引的轻微滥用。 您是否知道 REDUCE 语法中的 better/more 透明解决方案? 是否可以使用迭代变量的结构(整数、布尔值)? INDEX INTO
选项似乎不适用于 REDUCE。与内核版本 753(或更低版本)的兼容性会很好。
这是我的最小可重现示例 (MRE),它仅在 lvr_flag_allowed = abap_false OR
被注释掉时通过语法检查(即 -> "lvr_flag_allowed = abap_false OR
):
DATA: lt_itab TYPE TABLE OF i,
rv_flag_allowed TYPE boole_d.
lt_itab = VALUE #( ( 2 ) ( 1 ) ( -1 ) ( 5 ) ).
IF lt_itab IS NOT INITIAL.
rv_flag_allowed = REDUCE #( INIT lvr_flag_allowed = abap_true
FOR lvf_idx = 1 UNTIL lvr_flag_allowed = abap_false OR
lvf_idx > lines( lt_itab )
NEXT lvr_flag_allowed = xsdbool( lt_itab[ lvf_idx ] < 0 ) ).
ENDIF.
RETURN.
目前它给出了这个语法检查消息(它的ID是MESSAGEG[M
):
The variable "LVR_FLAG_ALLOWED" cannot be used here.
您知道这不起作用的技术原因吗? SAP documentation on REDUCE - Reduction Operator 仅表示
Usually the expression expr (after THEN) and the termination condition log_exp (after UNTIL or WHILE) depend on the iteration variable var.
因此,在写下这些内容时,我想到了一个解决方法 MRE:
DATA: lt_itab TYPE TABLE OF i,
* rv_flag_allowed TYPE boole_d,
rv_last_index TYPE i.
lt_itab = VALUE #( ( 2 ) ( 1 ) ( -22 ) ( 5 ) ( 7 ) ( 4 ) ).
IF lt_itab IS NOT INITIAL.
rv_last_index = REDUCE #( INIT lvr_last_index = 0
FOR lvf_idx = 1 THEN COND #( WHEN lt_itab[ lvf_idx ] < 0
THEN 0
ELSE lvf_idx + 1 )
UNTIL lvf_idx = 0 OR
lvf_idx > lines( lt_itab )
NEXT lvr_last_index = lvr_last_index + 1 ).
ENDIF.
RETURN.
它“双重”使用迭代索引和 returns rv_last_index = 3
。我现在返回一个整数而不是布尔值,以便检查正确的中止结果。这对你来说正确吗?
非常感谢您的反馈和改进建议(超越经典 while/until 循环 ;-))!
我实际上想用 line_exists
表达这一点,但不幸的是 table expressions only support equality comparisons(不幸的是不是 <
):
" invalid syntax v
DATA(some_negative) = xsdbool( line_exists( values[ table_line < 0 ] ) ).
稍微冗长但有效的变体是使用 LOOP AT
和直接 EXIT.
(是的,这不是“现代语法”,尽管 IMO 仍然非常可读):
DATA(some_negative) = abap_false.
LOOP AT values WHERE table_line < 0 TRANSPORTING NO FIELDS.
some_negative = abap_true.
EXIT.
ENDLOOP.
我不认为 REDUCE 是完成这项工作的正确工具,因为它应该将 table 理解为一个值(在其他语言中也没有短路,例如 .reduce
在 JS 中,尽管他们有其他方法用于此目的,如 .some
和 .every
等)。如果 truthy 行的数量很少,不对它们进行短路可能是可以接受的 table,并且这个 REDUCE
语句至少不会通过额外的 WHERE ( ... )
clause:
DATA(some_negative) = REDUCE abap_bool(
INIT result = abap_false
FOR entry IN values
WHERE ( table_line < 0 )
NEXT result = abap_true
).