2

为了检查内部表的所有条目是否lt_itab满足条件 COND,我想使用 REDUCE 语句。一旦发生违反 COND 的行,循环当然需要终止。再往下的第二个代码块似乎可以工作,但在我看来像是对迭代索引的轻微滥用。您是否知道 REDUCE 语法中有更好/更透明的解决方案?是否可以使用迭代变量的结构(整数,布尔值)?该INDEX INTO选项似乎不适用于 REDUCE。与内核版本 753(或更低版本)的兼容性会很好。

lvr_flag_allowed = abap_false OR这是我的最小可重现示例(MRE),它仅在被注释掉时才通过语法检查(即 -> "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):

此处不能使用变量“LVR_FLAG_ALLOWED”。

您知道这不起作用的技术原因吗?关于 REDUCE - Reduction Operator的SAP 文档仅说明

通常表达式 expr(在 THEN 之后)和终止条件 log_exp(在 UNTIL 或 WHILE 之后)取决于迭代变量 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.

它“双重”使用迭代索引并返回rv_last_index = 3。我现在返回一个整数而不是布尔值,以检查正确的中止结果。这对你来说是否正确?

非常感谢您的反馈和改进建议(除了经典的 while/until 循环 ;-))!

4

1 回答 1

5

我实际上想用 来表达这一点line_exists,不幸的是,表表达式只支持相等比较(遗憾的是不支持<):

"                                              invalid syntax v
DATA(some_negative) = xsdbool( line_exists( values[ table_line < 0 ] ) ).

一个稍微冗长但有效的变体是使用LOOP AT带有立即数的 a EXIT.(是的,这不是“现代语法”,尽管 IMO 仍然非常易读):

DATA(some_negative) = abap_false.
LOOP AT values WHERE table_line < 0 TRANSPORTING NO FIELDS.
  some_negative = abap_true.
  EXIT.
ENDLOOP.

我不认为 REDUCE 是适合这项工作的工具,因为它应该将表格理解为一个值(在其他语言中也没有短路,例如.reduce在 JS 中,尽管他们有其他方法可以做到这一点诸如此类的目的.some.every。如果真实行的数量很少,则可以接受不对它们进行短路,并且此REDUCE语句至少不会通过附加WHERE ( ... )子句访问虚假行:

DATA(some_negative) = REDUCE abap_bool(
  INIT result = abap_false
  FOR entry IN values
   WHERE ( table_line < 0 )
   NEXT result = abap_true
).
于 2021-11-04T17:33:26.743 回答