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

  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.

  7. #7
    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
    bonsoir pijaku
    oui c'est cette exeption que je voulais soulever
    et ca va plus loin que variant/variant
    dans la dll ca doit se faire tout seul visiblement

    regarde le resultat
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    Sub test()
    Dim v
    v = Array(1, 2, 3, "toto", 4, "titi")
    For i = LBound(v) To UBound(v)
    Debug.Print TypeName(v(i))
    Next
    End Sub
    la on voit bien que les nombres sont integer et les chaine en string
    ce qui est etonnant dans ma demo precedente c'est que tout les elements sont integer pourtant join fonctionne

    et pour la conversion des deux tableaux plus haut dans la discution c'est pareil rien que le fait de mettre v(x to y)as long et v2(x to y) as string ,fait que les elements de l'un dans l'autre se converti aumatiquement et se sera bien des string dans v2
    la conversion se passe surment dans la dll ce qui libere vba c'est pour ca peut etre que c'est plus rapide

    Nom : Capture.JPG
Affichages : 729
Taille : 44,5 Ko
    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

  8. #8
    Expert confirmé
    Homme Profil pro
    aucune
    Inscrit en
    Avril 2016
    Messages
    7 563
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 84
    Localisation : France, Pyrénées Atlantiques (Aquitaine)

    Informations professionnelles :
    Activité : aucune

    Informations forums :
    Inscription : Avril 2016
    Messages : 7 563
    Par défaut
    Bonsoir Franck

    Je n'ai personnellement rien à reprocher à ton tout premier mécanisme, qui a le mérite de traiter directement la chaîne à éclater.
    S'il est lent, ce n'est pas en raison du mécanisme en soi, mais en raison de la manière de le mettre en oeuvre.
    Regarde ce que fait ceci (tu vas comprendre) :
    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 = 500000
    Const MAX As Long = 3500000
    Const SEP As String = " - "
     
    Sub TestConversionCStr()
       Dim i As Long, j As Long, t As Double, coco As Long, base As String
       For j = MIN To MAX Step MIN
          ReDim v(j) As Long
          For i = LBound(v) To UBound(v)
             v(i) = i
          Next
          t = Timer
          base = Space$(100000000) ' je pense que ce tampon suffira 
          coco = 1
          For i = UBound(v) To UBound(v)
            Mid$(base, coco) = CStr(v(i))
            coco = coco + Len(v(i)) + 3 ' (ajout de la longueur du séparateur)
          Next
          MsgBox Timer - t & " pour  " & UBound(v)
       Next
    End Sub
    Amitiés
    Jacques

  9. #9
    Expert confirmé
    Avatar de Qwazerty
    Homme Profil pro
    La très haute tension :D
    Inscrit en
    Avril 2002
    Messages
    4 128
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France

    Informations professionnelles :
    Activité : La très haute tension :D
    Secteur : Service public

    Informations forums :
    Inscription : Avril 2002
    Messages : 4 128
    Par défaut
    Salut

    En espérant que ça n'a pas déjà été dit (je suis coutumier du fait en ce moment

    Dans tes deux cas (avec ou sans Cstr() , ça revient exactement au même pour moi, VBA étant un petit malin, il fait le transtypage lui même quand il en a besoin. Ce qui explique que cette ligne de code a$ = i$ ne provoque pas d'erreur en VB mais en provoque une en Delphi par exemple.
    Ainsi je doute que les différences de temps de calcule soient liées à ça ou alors disons plutôt que je ne me l'explique pas .

    @Unparia: Pour le coup du tampon, il est vrai que si j'y pense pour les tableaux en provoquant des redim preserve par lot de x lignes pour éviter l'éparpillement en mémoire, ça ne me vient pas de le faire pour les string utilisées de cette façon, ce qui pourtant revient au même finalement le string pouvant être vu comme un tableaux de char.
    De ce fait il est donc possible aussi d'ajouter du tampon à la suite si coco arrive au bout (mais ça ajoute un test qui sera fait à chaque boucle... quelques nanosecondes de temps de cycle à moins de gérer l'erreur provoqué par un dépassement - tout en veillant à ne pas dépasser la longueur max du string en ajoutant de grandes longueurs à chaque agrandissement du tampon)


    ++
    Qwaz

    MagicQwaz := Harry Potter la baguette en moins
    Le monde dans lequel on vit
    Ma page perso DVP
    Dernier et Seul Tutoriel : VBA & Internet Explorer
    Dernière contribution : Lien Tableau Structuré et UserForm
    L'utilisation de l’éditeur de message

  10. #10
    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
    Bonjour,

    @Qwazerty :
    Dans tes deux cas (avec ou sans Cstr() , ça revient exactement au même pour moi
    [...]
    Ainsi je doute que les différences de temps de calcule soient liées à ça
    Cela revient, en effet, à la même chose.
    Il n'y a pas de différence de calcul : sur 3 500 000, une différence de 0,4 seconde ne compte quasiment pas.
    Surtout qu'elle peut-être due à toute autre chose (utilisation du processeur par un autre programme par exemple).

    @Jacques :
    Merci pour ce code.
    Il est certain que le "dimensionnement" du String initialement, fait gagner énormément de temps d'exécution.
    Néanmoins, la méthode la plus rapide reste la 3ème de mon sujet : La conversion en Array de String SANS CStr et avec utilisation de la fonction Join.
    Mais merci pour ce rappel.

    Je pense que, sans autre manière de procéder (surtout ne pas hésiter à en proposer!), je vais conserver ce code :
    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

  11. #11
    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 rencontre maintenant, 2 difficultés.
    1. Dans ma fonction, le paramètre "tableau" doit être déclaré en Variant
      En effet, la fonction que je propose de construire, doit pouvoir gérer tous types de tableaux.
      Je veux pouvoir joindre des tableaux de Double, Date, Long, Currency, etc...
      Par conséquent, ma fonction doit être du genre :
      Code : Sélectionner tout - Visualiser dans une fenêtre à part
      Private Function xxJoin(Tableau As Variant, Separateur As String) As String
      Malheureusement, le fait de déclarer Tableau As Variant ralentit l'exécution du code de la fonction.
      Je transfère donc son contenu dans une variable tableau du bon type, en utilisant un Select Case VarType :
      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
       
      Dim i As Long, s() As String
         Select Case VarType(Tableau(LBound(Tableau)))
            Case 3
               Dim Lo() As Long: Lo = Tableau
               For i = LBound(Lo) To UBound(Lo)
                  s(i) = Lo(i)
               Next
            Case 5
               Dim Dou() As Double: Dou = Tableau
               For i = LBound(Dou) To UBound(Dou)
                  s(i) = Dou(i)
               Next
            Case 4
               Dim si() As Single: si = Tableau
               ...
         End Select
         xxJoin = Join(s, Separateur)
      Ma question pour ce point 1 est : le jeu en vaut-il la chandelle?
      En clair, plutôt que de faire un Select Case d'une vingtaine de choix, ne vaut-il mieux pas conserver le type Variant?

      D'autant plus qu'au final, je souhaite que cette fonction fonctionne également sur des tableaux à 2 dimensions.
      Tableaux qui, par définition, peuvent avoir des types différents selon les lignes/colonnes...

    2. La version 64 bits me "casse les pieds"...
      Cette déclaration ne fonctionne pas (erreur de compilation : type défini par l'utilisateur non défini) :
      Code : Sélectionner tout - Visualiser dans une fenêtre à part
      1
      2
      3
      4
      Private Function xxJoin(Tableau As Variant, Separateur As String) As String
      #If VBA7 Then
         Dim LL() As LongLong
      #End If
      Comment faire, si ce n'est laisser en Variant?


    Ps : après relecture et relecture de ce message, je crois vraiment qu'il convient de conserver le type Variant pour le paramètre "tableau".
    Je vous envoie toutefois ces questions afin d'obtenir vos avis.

    Merci

  12. #12
    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

    ben tu a ta reponse dans ta question en fait selon moi

    si ton but et de joindre de toute facon il faudra que ton tableau soit compatible on est d'accords?

    si je reflechi un peu comme tu veux joindre, le resultat ne sera plus une date ou un double ou un long ou autre mas tout simplement un string

    alors a quoi bon s'ennuyer a vouloir joindre un tableaux typé exactement comme les valeurs qu'il est sensé contenir ????

    non ton tableaux V2 doit etre un string tout simplement il acceptera tout

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    Sub test()
        Dim V(100)
        For i = 1 To 100
            V(i) = Date + i
        Next
        ReDim V2(UBound(V)) As String
        For i = LBound(V) To UBound(V)
            V2(i) = V(i)
        Next
    Debug.Print V(1) & "  :  " & TypeName(V(1))
    Debug.Print V2(1) & "  :  " & TypeName(V2(1))
     
    End Sub
    a ce que j'ai compris ta fonction est sensé refaire un tableau en compatible pour join donc le v2 doit etre en string tout simplement
    n'essaie pas de convertir element par element en string par cstr ou autre ca sert a rien ca le fait tout seul le tableau v2 est declaré avec des element string et il accepte tout et il le converti tout seul
    voir capture
    Nom : Capture.JPG
Affichages : 754
Taille : 92,5 Ko

    apres teste il faut 4 dizieme de secondes chez moi pour convertir un tableau de date de 100000 items en tableau compatible pour join . plus rapide il faut prendre rendez vous avec la nasa
    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 test()
        Dim V(100000) As Date
        For i = 1 To 10000
            V(i) = Date + i
        Next
        t = Timer
        ReDim V2(UBound(V)) As String
        For i = LBound(V) To UBound(V)
            V2(i) = V(i)
        Next
    t = Timer - t
    Debug.Print " V(1000): " & V(1000) & "  :  " & TypeName(V(1))
    Debug.Print " V2(1000):" & V2(1000) & "  :  " & TypeName(V2(1))
    Debug.Print t & " secondes"
    End Sub
    V(1000): 04/05/2021 : Date
    V2(1000):04/05/2021 : String
    0,046875 secondes
    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

  13. #13
    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,

    C'est exactement ce que je dis depuis le début.
    Côté code appelant : un tableau typé Long, Double, Date...
    Côté fonction "join" : un tableau de String.

    Après, l'utilisation ou non de la fonction de conversion CStr n'impacte quasiment pas.
    Comme déjà dit, 0.4 seconde pour un tableau de 3 000 000 d'éléments...

  14. #14
    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
    coté tableau initial rien net'empeche qu'il soit dimer correctement au contraire
    le remplissage est plus ou moins rapide selon le type ca se joue certe a 0,0000xxxx mais ca peut etre interessant pour des tres grands tableaux
    mais dans tout les cas le tableau final doit etre string car variant et string n'ont pas le meme poids
    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

  15. #15
    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
    Bonjour,

    Merci à tous.
    J'ai pu créer ma fonction JOINT que vous pourrez trouver ICI.

    A bientôt

  16. #16
    Membre Expert
    Profil pro
    Inscrit en
    Février 2007
    Messages
    2 266
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2007
    Messages : 2 266
    Par défaut
    Bonjour à tous,

    erreur, désolé du dérangement :-)
    Je voulais évoquer ByRef mais j'ai vu ton lien ensuite
    eric

  17. #17
    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
    Salut Eric,

    Oui, en effet, la fonction supporte bien le passage du tableau ByRef.
    Merci.

    A++

+ 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