3 Réponses :
Voici une solution qui ne répète pas la sélection, mais une question demeure, est-ce vraiment "mieux"?
La solution est basée sur la génération d'une ligne vide si le groupe de lignes contient une ligne avec le statut 'I1040 ', au lieu de garder la ligne indésirable. Je ne suis pas sûr, mais peut-être qu'une autre solution similaire pourrait conserver la référence à la ligne ( not_deleted
), en plus d'ajouter une variable auxiliaire pour savoir si la référence est à conserver ou non. J'ai trouvé plus intuitif d'utiliser les index de table ( INDEX INTO
), mais cela pourrait ne pas fonctionner si tt_struct
est un type de table hachée.
Je fournis le code avec un test unitaire ABAP afin que vous puissiez l'essayer rapidement vous-même.
CLASS ltc_main DEFINITION FOR TESTING DURATION SHORT RISK LEVEL HARMLESS. PRIVATE SECTION. METHODS test FOR TESTING. METHODS cut. TYPES : BEGIN OF ty_struct, guid TYPE string, stat TYPE string, END OF ty_struct, tt_struct TYPE STANDARD TABLE OF ty_struct WITH EMPTY KEY, t_ref_s_struct TYPE REF TO ty_struct. DATA: lt_ilot TYPE tt_struct, lt_valid_doc TYPE tt_struct. ENDCLASS. CLASS ltc_main IMPLEMENTATION. METHOD cut. lt_valid_doc = VALUE #( FOR ls_valid IN VALUE tt_struct( FOR GROUPS <group_key> OF <wa> IN lt_ilot GROUP BY ( guid = <wa>-guid ) ASCENDING LET x1 = REDUCE #( INIT x2 = 0 FOR <m> IN GROUP <group_key> INDEX INTO x3 NEXT x2 = COND #( WHEN <m>-stat = 'I1040' THEN -1 ELSE COND #( WHEN x2 <> 0 THEN x2 ELSE x3 ) ) ) IN ( COND #( WHEN x1 <> -1 THEN lt_ilot[ x1 ] ) ) ) WHERE ( table_line IS NOT INITIAL ) ( ls_valid ) ). ENDMETHOD. METHOD test. lt_ilot = VALUE #( ( guid = 'A' stat = 'I1000' ) ( guid = 'A' stat = 'I1040' ) ( guid = 'B' stat = 'I1020' ) ( guid = 'C' stat = 'I1040' ) ( guid = 'D' stat = 'I1040' ) ( guid = 'D' stat = 'I1000' ) ). cut( ). cl_abap_unit_assert=>assert_equals( act = lt_valid_doc exp = VALUE tt_struct( ( guid = 'B' stat = 'I1020' ) ) ). ENDMETHOD. ENDCLASS.
Hou la la! Je ne suis pas très expérimenté avec la syntaxe REDUCE et c'est une nouveauté pour moi de pouvoir construire des lignes avec des conditions de manière récursive, comme ceci NEXT x2 = COND # (WHEN stat = ... THEN -1 ELSE COND # (WHEN x2 < > 0 ALORS x2)
. Dans l'ensemble, je pense que votre solution est moins lisible et moins concise que la mienne)) Bien qu'elle ne filtre le statut qu'une seule fois, elle n'a cependant pas pu se débarrasser de la construction de tables imbriquées
La condition x1 <> -1
est littéralement la même que le second filtre d'état, donc pas de gain du tout, ni de performance ni de lisibilité.
La solution suivante n'est peut-être pas la plus jolie, mais elle est simple. Il est plus facile de supprimer un groupe entier si un membre remplit une condition que d'ajouter un groupe entier si tous échouent à la condition. Juste une idée.
TYPES : BEGIN OF ty_struct, guid TYPE string, stat TYPE string, END OF ty_struct, tt_struct TYPE STANDARD TABLE OF ty_struct WITH EMPTY KEY. DATA(lt_ilot) = VALUE tt_struct( ( guid = 'A' stat = 'I1000' ) ( guid = 'A' stat = 'I1040' ) ( guid = 'B' stat = 'I1020' ) ( guid = 'C' stat = 'I1040' ) ( guid = 'D' stat = 'I1040' ) ( guid = 'D' stat = 'I1000' )). LOOP AT lt_ilot INTO DATA(ls_ilot) WHERE stat = 'I1040'. DELETE lt_ilot WHERE guid = ls_ilot-guid. ENDLOOP.
Votre solution n'inclut pas de regroupement, plusieurs lignes avec le même guid sont possibles.
Si j'ai bien compris la demande de l'OP, le résultat attendu est la ligne unique "B I1020" (toutes les lignes des groupes avec I1040 doivent être supprimées).
J'espère vraiment que c'était une sorte de cas de test personnel, et vous n'utilisez pas ce codage dans un environnement productif. Si je devais comprendre ce que vous voulez réaliser en regardant uniquement le codage, je vous détesterais;).
La clé pour résoudre facilement ce problème est de trier le tableau de sorte que la condition de suppression soit toujours dans la première ligne de le groupe que vous souhaitez traiter:
Solution1 avec sortie de liste unique:
DATA: lt_bseg TYPE STANDARD TABLE OF t_s_bseg, lf_prev_belnr TYPE belnr, lf_delete TYPE char1. SORT lt_bseg BY belnr xnegp DESCENDING. LOOP AT lt_bseg ASSIGNING FIELD-SYMBOL(<ls_bseg>). IF <ls_bseg>-belnr <> lf_prev_belnr. lf_delete = <ls_bseg>-xnegp. lf_prev_belnr = <ls_bseg>-belnr. ENDIF. IF lf_delete = abap_true. DELETE lt_bseg. ENDIF. ENDLOOP.
Solution2
avec sortie de liste non unique:
DATA: lt_bseg TYPE STANDARD TABLE OF t_s_bseg. SORT lt_bseg BY belnr xnegp DESCENDING. DELETE ADJACENT DUPLICATES FROM lt_bseg COMPARING belnr. DELETE lt_bseg WHERE xnegp = abap_true.
Je vous détesterais
Je m'en fous :) Cela fonctionne et c'est l'essentiel.
Et btw, votre solution1 ne fonctionne que pour le cas primitif avec un champ binaire comme XNEGP, l'exemple principal avec un statut basé sur une chaîne I1040 ne fonctionne pas avec votre tri.
Cela aiderait beaucoup si c'était un exemple compilable avec toutes les dépendances fournies.
@Jagger a ajouté un exemple basé sur FI, mon cas vient de SRM donc difficilement reproductible par tout le monde