IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Macros et VBA Excel Discussion :

Fonction Join - Conversion d'un Array de type Long ou Double ou Date (etc) en Array de String


Sujet :

Macros et VBA Excel

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre Expert
    Avatar de pijaku
    Homme Profil pro
    Inscrit en
    Août 2010
    Messages
    1 817
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : France, Nord (Nord Pas de Calais)

    Informations forums :
    Inscription : Août 2010
    Messages : 1 817
    Billets dans le blog
    10
    Par défaut Fonction Join - Conversion d'un Array de type Long ou Double ou Date (etc) en Array de String
    Bonjour,

    Suite à cette contribution, je m'interroge aujourd'hui sur la fonction Join.

    En effet, celle-ci comporte des petits "manquements" :
    1. Elle ne traite que des Array de String,
    2. Elle ne traite que des Array à 1 dimension.


    Traitons ces deux cas l'un après l'autre.

    Test du passage, en paramètre de la fonction Join, d'un Array de type Long :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    Option Explicit
     
    Const MIN As Long = 5000
    Const MAX As Long = 35000
    Const SEP As String = " - "
     
    Sub DemoJoin()
    Dim i&, s$
       ReDim v(MIN) As Long
       For i = LBound(v) To UBound(v)
          v(i) = i
       Next
       On Error Resume Next
       s = Join(v, SEP)
       If Err.Number > 0 Then MsgBox Err.Description
       On Error GoTo 0
    End Sub
    Il nous faut donc convertir cet Array en String, pour cela il existe plusieurs méthodes de conversion.
    J'en connais personnellement 3, mais peut-être en auriez-vous une (ou plusieurs) autre(s) plus performante(s).

    1. Via une variable de type String intermédiaire :
      Le principe :
      On boucle sur notre Array (de type Long) et on stocke, à chaque boucle, son contenu dans une variable String.
      Le code de démo :
      Code : Sélectionner tout - Visualiser dans une fenêtre à part
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      Option Explicit
       
      Const MIN As Long = 5000
      Const MAX As Long = 35000
      Const SEP As String = " - "
       
      Sub TestViaString()
      Dim i&, j&, t#, s$
         Debug.Print "Méthode du String intermédiaire : "
         For j = MIN To MAX Step MIN
            ReDim v(j) As Long
            s = vbNullString
            For i = LBound(v) To UBound(v)
               v(i) = i
            Next
            t = Timer
            For i = LBound(v) To UBound(v)
               s = s & v(i) & SEP
            Next
            s = Left(s, Len(s) - Len(SEP))
            Debug.Print Right(s, Len(CStr(j))) & " ==> " & Timer - t & " sec. Lenght : " & Len(s)
         Next
      End Sub
      Les résultats :
      Méthode du String intermédiaire :
      5000 ==> 0,046875 sec. Lenght : 33894
      10000 ==> 0,201171875 sec. Lenght : 68895
      15000 ==> 0,494140625 sec. Lenght : 108895
      20000 ==> 0,9609375 sec. Lenght : 148895
      25000 ==> 1,611328125 sec. Lenght : 188895
      30000 ==> 2,595703125 sec. Lenght : 228895
      35000 ==> 6,689453125 sec. Lenght : 268895
      Conclusion :
      L'augmentation exponentielle de la durée d'exécution en fonction du nombre d'éléments à ajouter à notre variable String me fait conclure que cette manière de procéder n'est valable que sur de "petites" variables tableaux.

    2. La conversion en Array de String via CStr et utilisation de la fonction Join :
      Le principe :
      On passe les valeurs de notre Array de Long, dans un Array de String, en utilisant la fonction de conversion CStr.
      Une fois cette conversion réalisée, on utilise Join.
      Le code de démo :
      Ayant déjà testé, j'ai augmenté délibérément les valeurs des constantes MIN (de 5 000 à 500 000) et MAX (de 35 000 à 3 500 000).
      Code : Sélectionner tout - Visualiser dans une fenêtre à part
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      Option Explicit
       
      Const MIN As Long = 500000
      Const MAX As Long = 3500000
      Const SEP As String = " - "
       
      Sub TestConversionCStr()
      Dim i&, j&, t#, str$
         Debug.Print "Méthode de conversion (CStr) : "
         For j = MIN To MAX Step MIN
            ReDim v(j) As Long
            str = vbNullString
            For i = LBound(v) To UBound(v)
               v(i) = i
            Next
            t = Timer
            ReDim s(j) As String
            For i = LBound(v) To UBound(v)
               s(i) = CStr(v(i))
            Next
            str = Join(s, SEP)
            Debug.Print Right(str, Len(CStr(j))) & " ==> " & Timer - t & " sec. Lenght : " & Len(str)
         Next
      End Sub
      Les résultats :
      Méthode de conversion (CStr) :
      500000 ==> 0,54296875 sec. Lenght : 4388896
      1000000 ==> 1,3046875 sec. Lenght : 8888897
      1500000 ==> 2,01953125 sec. Lenght : 13888897
      2000000 ==> 2,751953125 sec. Lenght : 18888897
      2500000 ==> 3,548828125 sec. Lenght : 23888897
      3000000 ==> 4,26171875 sec. Lenght : 28888897
      3500000 ==> 5,05078125 sec. Lenght : 33888897
      Conclusion :
      On voit, en utilisant cette méthode, que l'augmentation de la durée d'exécution n'est plus exponentielle comme dans notre premier essai.
      Les temps peuvent paraître long (plus de 5 secondes) mais il faut relativiser.
      En effet, il n'est pas fréquent de croiser des Array de plus de trois millions d'éléments.

    3. La conversion en Array de String SANS CStr et avec utilisation de la fonction Join :
      Le principe :
      On passe les valeurs de notre Array de Long, dans un Array de String.
      Une fois cette conversion réalisée, on utilise Join.
      Le code de démo :
      Code : Sélectionner tout - Visualiser dans une fenêtre à part
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      Option Explicit
       
      Const MIN As Long = 500000
      Const MAX As Long = 3500000
      Const SEP As String = " - "
       
      Sub TestViaArrayString()
      Dim i&, j&, t#, str$
         Debug.Print "Méthode Array de String : "
         For j = MIN To MAX Step MIN
            ReDim v(j) As Long
            str = vbNullString
            For i = LBound(v) To UBound(v)
               v(i) = i
            Next
            t = Timer
            ReDim s(j) As String
            For i = LBound(v) To UBound(v)
               s(i) = v(i)
            Next
            str = Join(s, SEP)
            Debug.Print Right(str, Len(CStr(j))) & " ==> " & Timer - t & " sec. Lenght : " & Len(str)
         Next
      End Sub
      Les résultats :
      Méthode Array de String :
      500000 ==> 0,48828125 sec. Lenght : 4388896
      1000000 ==> 1,1640625 sec. Lenght : 8888897
      1500000 ==> 1,81640625 sec. Lenght : 13888897
      2000000 ==> 2,62890625 sec. Lenght : 18888897
      2500000 ==> 3,234375 sec. Lenght : 23888897
      3000000 ==> 4,609375 sec. Lenght : 28888897
      3500000 ==> 4,62109375 sec. Lenght : 33888897
      Conclusion :
      Les résultats des deux dernières méthodes sont équivalents.
      Cela m'amène à penser que l'une utilise l'autre en arrière-plan.
      Dans quel sens, cela je ne sait pas, et ça ne revêt pas un grand intérêt pour le sujet.


    Après cette mini étude, je pencherais pour la méthode de conversion avec CStr pour remédier au souci n° 1.
    J'ai également testé avec des Array de Double et de Date.
    Un "poil" plus lent, mais c'est entièrement normal, du aux "poids" différents de ces types de variable.

    2 questions donc :
    1. Verriez-vous une autre méthode?
    2. Les tests présentés ici (y compris ceux avec Double et Date) sont-ils suffisants?


    Merci déjà rien que pour la lecture de ce long sujet...

  2. #2
    Inactif  

    Homme Profil pro
    cuisiniste
    Inscrit en
    Avril 2009
    Messages
    15 374
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Var (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : cuisiniste
    Secteur : Bâtiment

    Informations forums :
    Inscription : Avril 2009
    Messages : 15 374
    Billets dans le blog
    8
    Par défaut re
    bonjour pijaku
    interessant
    reprend ton model TestViaArrayString mais redim v en string directement
    de quoi te faire tourner en bourrique hein !!???



    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    Sub TestViaArrayString()
    Dim i&, j&, t#, str$
       Debug.Print "Méthode Array de String : "
       For j = MIN To MAX Step MIN
          ReDim v(j) As String
          str = vbNullString
          For i = LBound(v) To UBound(v)
             v(i) = i
          Next
          t = Timer
          ReDim s(j) As String
          For i = LBound(v) To UBound(v)
             s(i) = v(i)
          Next
          str = Join(s, SEP)
          Debug.Print Right(str, Len(CStr(j))) & " ==> " & Timer - t & " sec. Lenght : " & Len(str)
       Next
    End Sub
    ben non en fait
    il ne faut pas oublier que les fonction elles memes que tu utilise prennent aussi de la memoire donc plus tu fera d'etapes dans ta convertion plus le temps d'execution sera plus long

    regarde les resultat

    Méthode Array de String avec l'array V en string au depart :
    500000 ==> 0,09375 sec. Lenght : 4388896
    1000000 ==> 0,234375 sec. Lenght : 8888897
    1500000 ==> 0,37109375 sec. Lenght : 13888897
    2000000 ==> 0,5 sec. Lenght : 18888897
    2500000 ==> 0,93359375 sec. Lenght : 23888897
    3000000 ==> 0,79296875 sec. Lenght : 28888897
    3500000 ==> 0,93359375 sec. Lenght : 33888897
    Méthode Array de String avec l'array V en long au depart :
    500000 ==> 0,18359375 sec. Lenght : 4388896
    1000000 ==> 0,421875 sec. Lenght : 8888897
    1500000 ==> 0,6875 sec. Lenght : 13888897
    2000000 ==> 0,91796875 sec. Lenght : 18888897
    2500000 ==> 1,16796875 sec. Lenght : 23888897
    3000000 ==> 1,40625 sec. Lenght : 28888897
    3500000 ==> 1,65625 sec. Lenght : 33888897
    comme tu peux le constater je divisee pratiquement le temps par 2 en string direct
    je supose que la conversion doit se faire dans la dll ce qui libere vba je dis bien je supose

    conclusion si tu veux du string dans ton tableau dimentionne le tout de suite en string meme si tu lui met des nombres
    mes fichiers dans les contributions:
    mail avec CDO en vba et mail avec CDO en vbs dans un HTA
    survol des bouton dans userform
    prendre un cliché d'un range

    si ton problème est résolu n'oublie pas de pointer : : ça peut servir aux autres
    et n'oublie pas de voter

  3. #3
    Membre Expert
    Avatar de pijaku
    Homme Profil pro
    Inscrit en
    Août 2010
    Messages
    1 817
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : France, Nord (Nord Pas de Calais)

    Informations forums :
    Inscription : Août 2010
    Messages : 1 817
    Billets dans le blog
    10
    Par défaut
    Patrick,

    Ce n'est pas le but du tout.
    Je sais que si je veux un Array contenant des String, même numériques, il convient de le dimensionner en String.
    Ce que je veux, c'est utiliser la fonction Join avec d'autres types de données que le String, dans un premier temps, bien entendu.
    Pour cela, il faut absolument convertir.
    Tu viens toutefois de me donner une autre idée que je vais m'empresser de tester...

    [EDIT] : Non, mauvaise idée...

  4. #4
    Inactif  

    Homme Profil pro
    cuisiniste
    Inscrit en
    Avril 2009
    Messages
    15 374
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Var (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : cuisiniste
    Secteur : Bâtiment

    Informations forums :
    Inscription : Avril 2009
    Messages : 15 374
    Billets dans le blog
    8
    Par défaut re
    re
    join convertit un tableau en string (chaine)
    je supose que la encore dans la fonction de la dll les element sont convertis en string pour correspondre entre eux afin de les joindre histoire de ne pas joindre une carrote et un poireaux
    enfin je supose
    moi aussi j'ai une idée de test
    apres je pense aussi que l'allocation de memoire d'une variable tableau est differente des autres variables (plus grande des le depart) la dimention n'est donc plus modifiée en cours de route
    tout du moins pour sa dimention tandis qu'un string evolutif sera recalculé a chaque tours
    mes fichiers dans les contributions:
    mail avec CDO en vba et mail avec CDO en vbs dans un HTA
    survol des bouton dans userform
    prendre un cliché d'un range

    si ton problème est résolu n'oublie pas de pointer : : ça peut servir aux autres
    et n'oublie pas de voter

  5. #5
    Inactif  

    Homme Profil pro
    cuisiniste
    Inscrit en
    Avril 2009
    Messages
    15 374
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Var (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : cuisiniste
    Secteur : Bâtiment

    Informations forums :
    Inscription : Avril 2009
    Messages : 15 374
    Billets dans le blog
    8
    Par défaut re
    re
    attention a la memoire qui joue des vilains tours aussi

    voici deux sub
    l'une en tableau de string l'autre qui converti en string dans un tableau2
    lance 2 ou 4 fois d'affilé la sub1 puis fait pareil avec la sub2 il y a des differences de temps avec la meme sub
    ensuite refait l'operation mais attends 1 seconde avant de relancer la meme sub et pareil pour la sub2

    tu constatera que la sub 2 met autant de temps que la sub1 malgré quelle fonctionne en deux boucle
    si ca c'est pas surprenant
    je dirais qu'il ne faut pas trop s'y fier moi en terme d'exactitude
    2 boucles qui mettent autant de temps qu'une ca me parrait un peu gros quand meme
    dans la sub 2 si tu fait un msgbox typename(v2(x)) tu aura bien un string pas besoins de cstr et autre la conversion c'est fait dans la dll

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    Option Explicit
     
    Const MIN As Long = 5000
    Const MAX As Long = 35000
    Const SEP As String = " - "
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    Sub string_danstablo_deXstring()
    Dim i&, s$, T
       ReDim v(1 To MAX) As String
        T = Timer
       For i = MIN To MAX
           v(i) = i
       Next
       T = Timer - T & " secondes"
        Debug.Print "teste avec tableau en string direct " & T '& vbCrLf & Join(v, ",") & vbCrLf & T
    End Sub
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    Sub string_danstablo_deXlong()
    Dim i&, s$, T
       ReDim v(1 To MAX) As Long
        T = Timer
       For i = MIN To MAX
          v(i) = CStr(i)
       Next
       ReDim v2(1 To MAX) As String
       For i = MIN To MAX
          v2(i) = v(i)
       Next
     
       T = Timer - T & " secondes"
       Debug.Print "teste avec tableau en long convertit en string dans tableau2 " & T '& vbCrLf & Join(v2, ",")
    End Sub
    le resultat en demo animé
    Pièce jointe 402196
    j'ai meme tester avec creation de la chaine avant le timer avec join ,et c'est bonnet blanc blanc bonnet


    pour etre honnete je suis plus préoccupé par cette ilogique ci dessous
    sachant dans la test2 si je le veux en string il me faudra mettre tout les items entre guillemets ou cstr la en l'occurence dans la test2 j'aurais une erreur 5 alors que l'array sans demander mon avis il est en string ou variant sinon je ne pourrais pas joindre
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    Sub test1()
    Dim v
    v = Array(1, 2, 3, 4, 5, 6, 7, 8, 9)
    Debug.Print Join(v, ",")
    End Sub
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    Sub test2()
    Dim v(9) As Long, i&
    For i = LBound(v) To UBound(v)
    v(i) = i + 1
    Next
    Debug.Print Join(v, ",")
    End Sub
    mes fichiers dans les contributions:
    mail avec CDO en vba et mail avec CDO en vbs dans un HTA
    survol des bouton dans userform
    prendre un cliché d'un range

    si ton problème est résolu n'oublie pas de pointer : : ça peut servir aux autres
    et n'oublie pas de voter

  6. #6
    Membre Expert
    Avatar de pijaku
    Homme Profil pro
    Inscrit en
    Août 2010
    Messages
    1 817
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : France, Nord (Nord Pas de Calais)

    Informations forums :
    Inscription : Août 2010
    Messages : 1 817
    Billets dans le blog
    10
    Par défaut
    Je vais donner le cas précis dans lequel Join serait utile avec d'autres types de valeur que des String.

    Je récupère, sur une feuille, des valeurs (Date, Double, Long, etc...), que je place dans un Array.
    Avec cet Array, j'effectue des calculs complexes (ou pas).
    Par conséquent, il faudrait, initialement, que cet Array soit typé selon le type de valeurs.
    Ceci afin de faciliter les calculs et ne pas alourdir l'exécution lors de ces calculs.

    Par conséquent, je ne peux pas partir d'un Array de String pour y placer mes valeurs.

    Ok, c'est bon maintenant?

    Le postulat de départ c'est :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    Sub Demo()
    Dim monTab() As Long 'ou As Date ou As Single etc...
    EDIT : Patrick,
    Ton test1 semble être le cas particulier, l'exception à la fonction Join.
    En effet, ta variable v est de type Variant.
    Tu l'alimentes via Array qui elle est une fonction qui renvoie une variable de type Variant contenant un tableau.
    Tu te retrouves donc, après son affectation, avec une variable v de type Variant/Variant qui ne déclenche pas l'erreur 5 lors de la fonction Join.

    Ton test2 est l'exemple typique de l'erreur 5 qu'il nous faut contourner dans le cas de figure exprimé ci-dessus.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Fonction de conversion de nombre en lettres
    Par david_chardonnet dans le forum Langage
    Réponses: 21
    Dernier message: 08/12/2021, 17h51
  2. Réponses: 5
    Dernier message: 01/12/2011, 08h38
  3. [Free Pascal] Fonction renvoyant un array of type
    Par zekiller3 dans le forum Free Pascal
    Réponses: 5
    Dernier message: 11/07/2007, 14h40
  4. Réponses: 5
    Dernier message: 12/01/2005, 20h58
  5. Fonction de conversion de COLORREF en hexadécimal?
    Par charliejo dans le forum MFC
    Réponses: 4
    Dernier message: 21/02/2004, 18h25

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo