1
votes

Création d'une plage pour un champ à partir d'une table interne à l'aide de RTTS

Je veux créer une fonction / méthode de classe personnalisée qui prend en 2 paramètres:

1) IM_ITAB type ANY TABLE

2) IM_COMPONENT type STRING

et renvoie 1 paramètre:

1) EX_RANGE type PIQ_SELOPT_T

Donc, l'algorithme est comme ceci:

  • Tout d'abord, nous vérifions si la colonne avec un nom de composant existe bien
  • Ensuite, nous vérifions que la table interne n'est pas vide.
  • Ensuite, nous parcourons la table interne d'affectation des composants et de la table de plage de remplissage. Le code est ci-dessous.
append corresponding fields of im_itab into new_line_type_internal_table.

Mais je veux encore améliorer la méthode. Si la table interne importée a, disons, 255 colonnes, il faudra plus de temps pour parcourir cette table. Mais je n'ai besoin que d'une seule colonne pour composer la plage.

Je veux donc obtenir les composants de la table interne, puis choisir un seul composant, créer un nouveau type de ligne contenant uniquement ce composant, puis créer une table interne avec cela type de ligne et copie.

Voici le pseudo code correspondant à ce que je veux réaliser:

METHODS compose_range_from_itab
    IMPORTING 
      IM_ITAB      type ANY TABLE
      IM_COMPONENT type STRING
    EXPORTING
      EX_RANGE     type PIQ_SELOPT_T.
...
METHOD compose_range_from_itab.

  DATA: lo_obj   TYPE REF TO cl_abap_tabledescr,
        wa_range TYPE selopt,
        lt_range TYPE piq_selopt_t.

  FIELD-SYMBOLS: <fs_line> TYPE ANY,
                 <fs_component> TYPE ANY.

  lo_obj ?= cl_abap_typedescr=>describe_by_data( p_data = im_itab ).

  READ TABLE lo_obj->key TRANSPORTING NO FIELDS WITH KEY name = im_component.

  IF sy-subrc IS INITIAL.

    IF LINES( im_itab ) GT 0.

      LOOP AT im_itab ASSIGNING <fs_line>.

        ASSIGN COMPONENT im_component OF STRUCTURE <fs_line> TO <fs_component>.

        wa_range-sign = 'I'.
        wa_range-option = 'EQ'.
        wa_range-low = <fs_component>.

        APPEND wa_range TO lt_range.

      ENDLOOP.

      SORT lt_range BY low.
      DELETE ADJACENT DUPLICATES FROM lt_range COMPARING low.

      ex_range[] = lt_range[].

    ENDIF.

  ENDIF.

ENDMETHOD.

Comment puis-je "découper" un composant et créer un nouveau type de ligne en utilisant RTTS?


4 commentaires

Avoir 255 colonnes ou même 1000 colonnes n'aura aucun impact sur votre algorithme car vous utilisez LOOP AT ... ASSIGNING (seule l'utilisation de INTO aurait un impact). RTTS peut améliorer les performances, mais uniquement lorsque vous utilisez le tableau des plages, mais le gain est probablement très très faible. Alors, votre question concerne-t-elle vraiment l'utilisation de RTTS, ou avez-vous un problème de performances ou un autre problème?


Même question posée sur SCN (pas encore de réponse pour l'instant)


@Sandra, "Avoir 255 colonnes ou même 1000 colonnes n'aura aucun impact sur votre algorithme" ne semble pas tout à fait correct. Je suppose que le ASSIGN COMPONENT [...] OF STRUCTURE [...] varie avec le nombre de colonnes dans le tableau. Au moins ma variante ci-dessous suggère qu'il y a une différence.


@Florian il n'y a pas de différence car il n'y a pas de boucle sur les composants, un seul composant est vérifié pour chaque ligne.


3 Réponses :


1
votes

Vous êtes en train de tout compliquer, vous n'avez pas besoin de RTTS pour cela.

DEFINE make_range.
  ex_range = VALUE #( BASE ex_range ( sign = 'I' option = 'EQ' low = &1 ) ).
END-OF-DEFINITION.

LOOP AT im_itab ASSIGNING FIELD-SYMBOL(<fs_line>).
  ASSIGN COMPONENT im_component OF STRUCTURE <fs_line> TO FIELD-SYMBOL(<fs_field>).
  CHECK sy-subrc = 0 AND <fs_field> IS NOT INITIAL.
  make_range <fs_field>.
ENDLOOP.

Et oui, comme l'a dit Sandra, vous ne gagnerez aucune performance avec RTTS, bien au contraire.

/ p>


2 commentaires

Je ne ferais pas le CHECK sy-subrc encore et encore. Il suffit de le faire une fois pour toute la table, et non de le répéter pour chaque ligne. Le composant est soit là dans toutes les lignes ou non. Assurez-vous également que AND IS NOT INITIAL est vraiment prévu - avoir une option I EQ pourrait en fait être le comportement souhaité.


Pour être sûr, je suppose que la vérification de l'affectation des symboles de champ à chaque fois n'est pas mauvaise, mais je conviens que c'est redondant. Ajouté pour la concision du code, car la vérification avant la boucle nécessite plus de lignes de code. Et je ne pouvais pas convenir que l'ajout de plusieurs espaces à la table de plage est une bonne idée, cela pourrait impliquer des ballonnements de plage sur les ensembles de données d'enchères, ce qui n'est pas bon. OP peut ajouter un espace unique à la plage si nécessaire.



0
votes

Étonnamment, cette variante s'est avérée plus rapide:

CLASS-METHODS make_range_variant_2
  IMPORTING
    sample        TYPE table_type
    column        TYPE string
  RETURNING
    VALUE(result) TYPE range_type.

METHOD make_range_variant_2.

  TYPES:
    BEGIN OF narrow_structure_type,
      content TYPE char32,
    END OF narrow_structure_type.

  TYPES narrow_table_type TYPE STANDARD TABLE OF narrow_structure_type WITH EMPTY KEY.

  DATA narrow_table TYPE narrow_table_type.

  DATA(mapping) =
    VALUE cl_abap_corresponding=>mapping_table_value(
      ( kind = cl_abap_corresponding=>mapping_component srcname = column dstname = 'CONTENT' ) ).

  DATA(mover) =
    cl_abap_corresponding=>create_with_value(
      source      = sample
      destination = narrow_table
      mapping     = mapping ).

  mover->execute(
    EXPORTING
      source      = sample
    CHANGING
      destination = narrow_table ).

  LOOP AT narrow_table ASSIGNING FIELD-SYMBOL(<row>).

    INSERT VALUE #(
        sign   = 'I'
        option = 'EQ'
        low    = <row>-content )
      INTO TABLE result.

  ENDLOOP.

ENDMETHOD.

CL_ABAP_CORRESPONDING délègue à une fonction du noyau pour le déplacement de structure à structure, qui est apparemment plus rapide que le ASSIGN COMPONENT OF STRUCTURE [...] TO FIELD-SYMBOL [...] natif d'ABAP. La boucle réelle semble alors être plus rapide car elle utilise des attributions de noms fixes.

Peut-être que quelqu'un pourrait vérifier.


5 commentaires

vous supposez que le type du composant est char32?


malheureusement cl_abap_corresponding ne prend pas en charge table_line.


Pour l'exemple de code, j'ai simplement supposé un type, oui. Si le type n'est pas connu, cela n'est pas possible car la narrow_table ne peut pas être déclarée de manière statique.


cette variante s'est avérée plus rapide quelles sont vos preuves? Avez-vous effectué une analyse comparative?


Voici les variantes que j'ai utilisées: github.com/HrFlorianHoffmann/AbapSammaster/AbapSammaster /…



0
votes

Je n'irais pas pour un Macro.

Data:
      lr_data type ref to data.

FIELD-SYMBOLS:
      <lv_component> TYPE any,
      <ls_data> TYPE any.

CREATE DATA lr_data LIKE LINE OF im_itab.
ASSIGN lr_data->* TO <ls_data>.

"Check whether im_component exists
ASSIGN COMPONENT im_component OF STRUCTURE <ls_data> TO <lv_component>.

CHECK sy-subrc EQ 0.

LOOP AT im_itab INTO <ls_data>.
  APPEND VALUE #( sign = 'I' option = 'EQ' low = <lv_component> ) TO ex_range.
ENDLOOP.


3 commentaires

Marco Polo?)) Mais j'apprécie votre code, c'est logique


@Suncatcher J'espère que vous avez compris ce que je voulais dire. Il est déconseillé d'utiliser Macro dans la plupart des langages de programmation modernes. Bien sûr, vous pouvez en discuter. Juste FYI .


D'accord, c'est déconseillé. Mais cela rend le code plus concis et plus lisible et est autorisé dans les one-liners primitifs (remplissage de cellules, structures, etc.) où le débogage n'est pas indispensable