XL 2021 Vos avis SVP: Une fonction TRANSPOSE() à améliorer

Boostez vos compétences Excel avec notre communauté !

Rejoignez Excel Downloads, le rendez-vous des passionnés où l'entraide fait la force. Apprenez, échangez, progressez – et tout ça gratuitement ! 👉 Inscrivez-vous maintenant !

p'tit vieux

XLDnaute Occasionnel
Bonjour à tous,
Pour mes codes VBA, j'ai écris une première version de ma fonction Transpose() que je vais mettre à votre disposition dans sa version 1.0.0.
Toutefois, je voudrais votre avis sur l'intérêt de rajouter des options complémentaires à celle-ci.

Dans un premier temps j'ai écris une fonction Transpose() afin de lever la limite des 65536 lignes de la fonction "WorkSheetFunctions.Transpose" d'Excel.
Pour mes besoins j'ai ajouté les possibilités suivantes:
- Choisir la base départ du tableau (Base 0 ou 1)
- Pouvoir convertir un texte/valeur simple dans un tableau 2D T(1,1)

Rien d'exceptionel, mais pratique.

Donc je vous propose de me soumettre vos idées.

Par exemple, j'ai pensé à:
- Si on transmet T(0 to 0, 0 to N) ou T(1 to N, 1 to 1) Transpose() renvoie un tableau 1D T(0 to N) ou T(1 to N) suivant la base choisie
- Transposer ET ne renvoyer que les n premieres lignes
- Transposer ET ne renvoyer de la ligne n° X à n° Y

Voilà pour ces quelques idées.
A votre avis laquelle ou lesquelles de celles-ci ont-elles un intérêt.

Et vous, vos autres idées qui vous paraitraient utiles?
Ensuite suivant vos propositions ….
Je nommerai un 1er Ministre du développement 🤣
Mais non! Je publierai une nouvelle version (Pas sérieux ces P'tit Vieux)

Merci pour vos avis et suggestions.

ATTENTION!
Ici il n'est pas question de faire des recherches de texte/valeur ou autre truc du genre.
 
Dernière édition:
Bon, alors puisque @mapomme a répondu, je vais aussi donner quelques précisions et après je m'arrête là.
sauf que dans l'absolu cette fonction transpose n'est pas sensée modifier les bases
et mettre +1 c'est forcer le transpose en base 1
A noter que dans mon code, je met la base de sortie à n'importe quelle valeur si on le souhaite (0, 1, -3, +5, etc...) et je ne présuppose pas d'un base 0 ou 1 du tableau d'entrée car elle peut être différente.
Excel le permet, c'est le choix de l'utilisateur selon ses besoins propres.

1734009073734.png


Le + 1 n'a rien à voir avec la base, c'est un + 1 dans la boucle de chargement pour éviter d'avoir un calcul dans l'indice.

Version avec indice calculé (k + i et p + j):
Code:
k = LBound(t, 1) - 1
p = LBound(t, 2) - 1
For i = 1 To ni
    For j = 1 To nj
        r(j, i) = t(k + i, p + j)
    Next j
Next i

Version avec indices directs en variables (k et p) évoluant en + 1 dans la boucle:
VB:
k = LBound(t, 1)
For i = 1 To ni
    p = LBound(t, 2)
    For j = 1 To nj
        r(j, i) = t(k, p)
        p = p + 1
    Next j
    k = k + 1
Next i

La version en +1 est plus performante de 2% à 3%.

mis a part que avec ses api on descend jusqu'au nano
ça n'a pas très grand intérêt (a mon grand regret
Même si de légères variations sont inévitables, le test comparatif me semble tout à fait valide.
Y aurait-il mieux ? Peut-être mais il faudrait trouver quoi, et c'est pas si mal de disposer d'un petit code à 2 balles du Module_MicroTimer ou à 10 balles avec cBenchmark.

c'est pour cela que j'utilise "sgn" qui me donne l'indice en plus ou en moins en une même ligne et même instruction
autrement dit le +1 ou -1 ou +0 est calculé par sgn seulement deux fois
La fonction Sgn() donne le signe d'un nombre.
Hormis le fait que tu supposes que le tableau d'entrée est en base 1 ou 0 (ce qui est une pure hypothèse), l'utilisation de Sgn() est faite pour déterminer la base du tableau transposé, pas dans une boucle.
C'est fait en début de code et que ce soit Sgn() ou un test ça ne change rien à la performance globale qui est déterminée ici par les boucles de chargement du tableau transposé.
 
oui je suis d'accord pour le module
je m'en suis fait un comme tu a pu le voir dans les captures mais c'est le reste ou je ne suis pas d'accords avec toi
c'est ta logique + ou moins ce que tu veux sur un lbound et ubound(2dimensions) qui eux sont déjà fixés
sans des if et des else ce n'est pas possible
et c'est en ça que le sgn est plus rapide la valeur sera automatiquement -1 ou 0 ou 1
si tu veux une base par exemple (-3) tu peux pas appliquer -3 sur le lbound ou ubound sans en connaitre les valeurs
ou l'appliquer dans le transfert ce qui reviens au même calcul il y a

dans mes tests sgn et +1 testé respectivement l'un après l'autre 500 fois
dans les plus petits score de l'un et de l'autre sgn fait 1.5 ms de moins
après tu fait peut être autrement c'est ta logique qu'il faut me donner pour que je teste
pas ton code juste ta logique en 3/4 lignes
 
Bonsoir à tous,
avant désolé d'avoir dû déserté le sujet que j'ai initié.
Mes excuses de n'avoir pu y participé.

Depuis hier soir j'ai essayé de me "mettre à jour".
Y en a qui se sont un peu écarté voire "éclaté façon puzzle" du sujet initial. 😁
Sur l'objet de la question de départ les algos proposés y répondent.
(Même si certain(s) veux/veulent censuré(s) les fonctionnalités car, avec à priori, idiotes . 😂)
En tout cas MERCI les 💪🏻 d'avoir amélioré ma version de départ.

Je vais synthétiser tout ça après avoir mis la fonction dans 1 ou 2 de mes fonctions pour voir dans mes cas réels l'amélioration. Je suis sûr qu'elle va être importante.
Après je mettrai la version 2 à disposition dans les ressources (en ne manquant pas de faire référence à vos contributions bien sûr).

Je finis cela et vous mettrai le résultat ici avant publication.
 
Eh ben! Si j'avais su que ma question allait autant de réponses

Autre sujet … Le chronométrage.
Très intéressant le sujet du cBenchMark pour savoir si mes chronos sont bons et si ont peut faire mieux et plus facilement.
Après avoir lu vos (très) nombreux post sur le sujet …
Point n°1, parce que vous vous l'avez fait, je ne suis pas rentré dans le détail du code de la classe cBenchMark.
Point n°2, je me suis arrêté à son utilisation
En tant qu'utilisateur, suite à vos posts, j'ai fait 2 tests

Test1:
Entre chaque appel à Transpose j'ai vidé toutes les variables et réinitialisé la classe cBenchMark.
C'est mieux, plus constant mais bof.
Conclusion:
- Pas convaincu de la facilité d'utilisation pour chronométrer des fonctions, classes et autres Sub de nos codes VBA.
- A vous lire, la fiabilité des chronos sont limites. J'ai pu constater la même chose.

Test2:
Je me suis livré à simple comparatif BASIQUE entre TIMER (comme je le fais actuellement) et la classe cBenchMark.
Le résultat du test se fait sur un tableau 2D de 5 millions de données REMPLI par des chaines
Voici le code remplissage (rien de génial):
VB:
ReDim Tablo([B]1[/B] To 5000, [B]0[/B] To 1000)    '50 millions de données
'''''''''
' Remplir avec du TEXTE
  If QDim = 2 Then
    For I = LBound(Tablo) To UBound(Tablo)
      For J = LBound(Tablo, 2) To UBound(Tablo, 2)
        Tablo(I, J) = CStr(I) & ", " & CStr(J)
      Next J
    Next I
  Else
    For I = LBound(Tablo) To UBound(Tablo)
      Tablo(I) = CStr(I)
    Next I
  End If
'''''''''
En même temps jai mis les 2 façons: Timer et la classe cBenchMark AVEC réinitialisation de la classe et des variables entre chaque Transpose()
J'ai testé le code de Patrick, Dudu2 (post #166), le mien (très largement copier/coller du code de Dudu2 -post #38-)

============
Dudu2 Base(1) / Base(2) Tablo: 1 / 0
Dudu2 Base(1) / Base(2) Results: 0 / 1
CHRONO Timer #166: 1,984 s
IDnr Name Count Sum of tics Percentage Time sum
0 Debut Transpose Dudu2 #166 1 21 283 502 51,81% 2,13 s
1 Fin Transpose Dudu2 #166 1 19 798 203 48,19% 1,98 s
TOTAL 2 41 081 705 100,00% 4,11 s

Total time recorded: 4,11 s

============
Vx Base(1) / Base(2) Tablo-> 1 / 0
Vx Base(1) / Base(2) Results-> 0 / 1
CHRONO Timer: 1,789 s
IDnr Name Count Sum of tics Percentage Time sum
0 Debut Transpose P'tit Vieux 1 4 513 842 20,16% 451 ms
1 Fin Transpose P'tit Vieux 1 17 875 859 79,84% 1,79 s
TOTAL 2 22 389 701 100,00% 2,24 s

Total time recorded: 2,24 s

============
Patrick Base(1) / Base(2) Tablo-> 1 / 0
Patrick Base(1) / Base(2) Results-> 0 / 1
CHRONO Timer: 1,844 s
IDnr Name Count Sum of tics Percentage Time sum
0 Debut Transpose Patrick 1 4 923 645 21,07% 492 ms
1 Fin Transpose Patrick 1 18 440 717 78,93% 1,84 s
TOTAL 2 23 364 362 100,00% 2,34 s

Total time recorded: 2,34 s
Le temps TOTAL de la classe me semble ne pas servir dans ce cas. Non?
Par contre si on teste plusieurs Fonctions/Sub en même temps là OK. Mais ça me semble lourd et sur mon test pas de différence de chrono entre Tics et Timer.

Donc soit j'utilise mal la classe soit c'est char pour tuer un moustique.

Merci à vous
A bientôt
 
re
bonsoir @p'tit vieux ha ben ça c'est certain c'est un bazooka pour tuer un chtique
ce module a la base est fait pour les développeur et même amateur pour tester la vélocité de leur algo
c'est sur qu’après résolution des problèmes relevés (même si il y a des effets de bord il donne quand même des indications sur les parties a améliorer si tant est qu'elles aient été testé )
il faut l'enlever il n'a rien a faire ou rester dans un fichier

je pense que c'était nécessaire de débattre la dessus car je pense que ça nous a tous aidé a améliorer nos algo selon nos méthodes et convictions respectives moi le premier
 
@p'tit vieux,
Pour revenir à l'algorithme de Transpose, suite aux cogitations sur les Bases (LBound) du tableau transposé, au lieu d'avoir 1 paramètre commun pour les 2 dimensions, je me suis dit que ce serait mieux d'en avoir 1 par dimension. C'est assez théorique mais si Excel le permet, why not !
VB:
'- BaseOut1 : Optionnel - 0 ou 1 ou autre valeur selon le LBound souhaitée de la 1ère dimension du tableau transposé
'             xlNone pour utiliser le LBound de la 2ème dimension de t
'- BaseOut2 : Optionnel - 0 ou 1 ou autre valeur selon le LBound souhaitée de la 2ème dimension du tableau transposé
'             xlNone pour utiliser le LBound de la 1ère dimension de t

D'où ce nouveau fichier joint et ces résultats un peu exotiques possibles:

1734031277230.png


1734031219809.png
 
A propos de Transposer j'ai une question à la foule des passionnés hurlants.

Comment faut-il transposer un tableau t à 1 dimension ?
  1. Comme Excel en passant la dimension de t en 2éme dimension et en ayant la 1ère dimension à 1 ?
  2. En gardant la 1ère dimension telle quelle et en ajoutant simplement une 2ème dimension à 1 ?
Un Transpose serait plutôt l'option 1 non ? Qu'en pensez-vous ?
Quoique l'option 2 est intéressante pour placer un tableau à 1 dimension dans un Range.
Alors une option pour savoir faire les 2 ?
 
c'est vrai ça why not
VB:
'VERSION 1
Function TransposeXV1(T, Optional lBase1& = -1, Optional lBase2& = -1)
    'patricktoulon    V 1.2 -- 08/07/2021
    'Ajout du change base V 1.2.1 -- 08/12/2024  méthode Addition nombre relatif
    Dim y&, i&, C&, T2(), LB1%, LB2%
    If TypeOf T Is Range Then T = T.Value
    If Not IsArray(T) Then TransposeXV1 = T
    If lBase1 > 1 Then lBase1 = 1 ' au cas ou il vous prendrez l'envie de faire nimporte quoi
    If lBase2 > 1 Then lBase2 = 1 ' au cas ou il vous prendrez l'envie de faire nimporte quoi
    On Error Resume Next
    y = UBound(T, 2)
    On Error GoTo 0
    'b1 et b2 deviendront les reducteurs ou augmenteur de dimension (++/+-)
    If lBase1 > -1 Then LB1 = Sgn(lBase1 - LBound(T))
    If y = 0 Then
        ReDim T2(LBound(T) + LB1 To UBound(T) + LB1, LBound(T) + LB1 To LBound(T) + LB1)
    Else
        If lBase2 > -1 Then LB2 = Sgn(lBase2 - LBound(T, 2))
        ReDim T2(LBound(T, 2) + LB2 To UBound(T, 2) + LB2, LBound(T) + LB1 To UBound(T) + LB1)
    End If
    For i = LBound(T) To UBound(T)
        If y = 0 Then
            T2(i + LB1, 1) = T(i)
        Else
            For C = LBound(T, 2) To UBound(T, 2)
                T2(C + LB2, i + LB2) = T(i, C)
            Next
        End If
    Next
    TransposeXV1 = T2
End Function

'VERSION 2
Function TransposeXV2(T, Optional lBase1& = -1, Optional lBase2& = -1)
    'Ajout du change base V 1.2.1 -- 08/12/2024  méthode Addition nombre relatif en select case
    'patricktoulon    V 1.3 -- 10/12/2024
    'version 1.3 avec un select case
    Dim y&, i&, C&, T2(), LB1%, LB2%
    If TypeOf T Is Range Then T = T.Value
    If Not IsArray(T) Then TransposeXV2 = T
    If lBase1 > 1 Then lBase1 = 1 ' au cas ou il vous prendrez l'envie de faire nimporte quoi
    On Error Resume Next
    y = UBound(T, 2)

    'b1 et b2 deviendront les reducteurs ou augmenteur de dimension (++/+-)

    Select Case True
        Case Err.Number <> 0
            If lBase1 > -1 Then LB1 = Sgn(lBase1 - LBound(T))
            ReDim T2(LBound(T) + LB1 To UBound(T) + LB1, LBound(T) + LB1 To LBound(T) + LB1)
            For i = LBound(T) To UBound(T): T2(i + LB1, 1) = T(i): Next
            On Error GoTo 0
        Case Else
            If lBase2 > -1 Then LB2 = Sgn(lBase2 - LBound(T, 2))
            ReDim T2(LBound(T, 2) + LB2 To UBound(T, 2) + LB2, LBound(T) + LB1 To UBound(T) + LB1)
            For i = LBound(T) To UBound(T)
                For C = LBound(T, 2) To UBound(T, 2): T2(C + LB2, i + LB2) = T(i, C): Next
            Next
    End Select
    TransposeXV2 = T2
End Function
A propos de Transposer j'ai une question à la foule des passionnés hurlants.

Comment faut-il transposer un tableau t à 1 dimension ?
  1. Comme Excel en passant la dimension de t en 2éme dimension et en ayant la 1ère dimension à 1 ?
  2. En gardant la 1ère dimension telle quelle et en ajoutant simplement une 2ème dimension à 1 ?
Un Transpose serait plutôt l'option 1 non ? Qu'en pensez-vous ?
Quoique l'option 2 est intéressante pour placer un tableau à 1 dimension dans un Range.
Alors une option pour savoir faire les 2 ?
ben c'est simple on rajoute la dim 2
et la dim 2 devient la 1 et la 1 devient la 2 c'est dans la logique de transposition non

sinon ce n'est pas une transposition c'est une conversion
j'ai dis conversion ok
VB:
'FONCTION DE CONVERSION  D'UN ARRAY VERS TABLEAU 2 DIM
Function ConvertTo2Dim(ByVal T As Variant) As Variant
    'patricktoulon    V 1.0 -- 06/12/2024
    Dim T2(), i&, y&
    If Not IsArray(T) Then ConvertTo2Dim= T
    If GetTypeArray(T) > 1 Then ConvertTo2Dim = T: Exit Function
    ReDim T2(LBound(T) To LBound(T), LBound(T) To UBound(T))
    For i = LBound(T) To UBound(T): T2(LBound(T), i) = T(i): Next i
    ConvertTo2Dim = T2
End Function
et la petite fonction GetTypeArray qui va bien
ici on gerrera l'erreur comme VBA le fait avec une erreur stopante sauf si gestion d'erreur dans l'appel
bref classique quoi
Code:
'FONCTION POUR DETERMINER LE TYPE D ARRAY(1 ou 2 dim)
Function GetTypeArray(T)
    'patricktoulon    V 1.0 -- 06/12/2024
    Dim U2
    If Not IsArray(T) Then GoSub Errorx
    On Error Resume Next
    U2 = UBound(T, 2)
    If Err Then
        GetTypeArray = 1
        On Error GoTo 0
    Else
        GetTypeArray = 2
    End If
    Exit Function
Errorx:     Err.Raise Number:=2002, Description:="Fonction : GetTypeArray" & vbCrLf & "L'argument reçu n'est pas un array ."
End Function

j'en ai tout un module comme ca
que j'ai publié d'ailleurs
🤣 🤪
 
Dernière édition:
@patricktoulon, merci pour ta contribution. Je pense que la foule se retient de hurler... pour le moment 😩

Conséquemment, j'ai ajouté une option pour le traitement des tableaux à 1 dimension.
VB:
'- t            : Range ou Table à 1 ou 2 dimensions ou une valeur
'- BaseOut1     : Optionnel - 0 ou 1 ou autre valeur selon le LBound souhaitée de la 1ère dimension de la table transposée
'                 Par défaut: xlNone pour utiliser le LBound de la 2ème dimension de la table t
'- BaseOut2     : Optionnel - 0 ou 1 ou autre valeur selon le LBound souhaitée de la 2ème dimension de la table transposée
'                 Par défaut: xlNone pour utiliser le LBound de la 1ère dimension de la table t
'- NoTranspose  : Optionel - True pour ne pas transposer une table à 1 dimension et seulement lui rajouter une 2ème dimension
'                 Par défaut: False
'- Return       : Table à 2 dimensions transposée de t (sauf cas NoTranspose = True)
 

Pièces jointes

A propos de Transposer j'ai une question à la foule des passionnés hurlants.

Comment faut-il transposer un tableau t à 1 dimension ?
  1. Comme Excel en passant la dimension de t en 2éme dimension et en ayant la 1ère dimension à 1 ?
  2. En gardant la 1ère dimension telle quelle et en ajoutant simplement une 2ème dimension à 1 ?
Un Transpose serait plutôt l'option 1 non ? Qu'en pensez-vous ?
Quoique l'option 2 est intéressante pour placer un tableau à 1 dimension dans un Range.
Alors une option pour savoir faire les 2 ?
Bonsoir @Dudu2
Pour moi je fais simple et suivrais la logique maths:
Le chiffre 4 n’est que 4/1. "L’inverse" d’un entier 4 est 1/4.
Donc t(5) => t(1/5)
Ça c’est MA logique.
Inversement transposer T(base to base , 1 to N) devrait devenir T(base to N) car "l’inverse" de 1/4 => 4. 😉
Et si c’est T(base to N, base to base) ?
Question?
Maintenant il peut être nécessaire de ne PAS être logique 😀 .donc pourquoi ne pas laisser le choix ?
Comme tu le dis toi même si on veux afficher un zone Rangé de vertical en horizontal ou inversement c’est intéressant 😀

La foule à répondu 😉
 
Merci @p'tit vieux pour tes réponses algébriques.
Ce que tu préconises est ce que fait Excel avec son Application.Transpose.

Donc t(5) => t(1/5)
C'est ce que fait maintenant la fonction TransposeNaturel.
J'ai quand même mis en place une option NoTranspose (False par défaut) qui si définie à True, fait t(5) = t(5/1) car cela a une réelle utilité pour valoriser un Range.

Par contre, la fonction NE fait PAS l’inverse" de t(1/4) => t(4). Elle fait t(1/4) => t(4/1).
J'hésite à ce qu'elle fasse t(1/4) => t(4) et voire sur option Transpose fasse t(1/4) => t(4/1) pour avoir une symétrie.

Mais ça m'embête car cette réduction de dimensions c'est mon cauchemar avec Excel car en codant je ne sais plus qu'est-ce qui se trouve dans la table et comment. Et plus j'aoute de paramètres moins c'est lisible et facile à utiliser. Et puis j'aime assez l'idée de toujours retourner une table à 2 dimensions.

Ou alors j'ajoute un paramètre LikeExcel qui vaut pour les 2 sens t(5) => t(1/5) et t(1/5) =>t(5)
 
Dernière édition:
Merci @p'tit vieux pour tes réponses algébriques.
Ce que tu préconises est ce que fait Excel avec son Application.Transpose.


C'est ce que fait maintenant la fonction TransposeNaturel.
J'ai quand même mis en place une option NoTranspose (False par défaut) qui si définie à True, fait t(5) = t(5/1) car cela a une réelle utilité pour valoriser un Range.

Par contre, la fonction NE fait PAS l’inverse" de t(1/4) => t(4). Elle fait t(1/4) => t(4/1).
J'hésite à ce qu'elle fasse t(1/4) => t(4) et voire sur option Transpose fasse t(1/4) => t(4/1) pour avoir une symétrie.

Mais ça m'embête car cette réduction de dimensions c'est mon cauchemar avec Excel car en codant je ne sais plus qu'est-ce qui se trouve dans la table et comment. Et plus j'aoute de paramètres moins c'est lisible et facile à utiliser. Et puis j'aime assez l'idée de toujours retourner une table à 2 dimensions.

Ou alors j'ajoute un paramètre LikeExcel qui vaut pour les 2 sens t(5) => t(1/5) et t(1/5) =>t(5)
Tu as raison sur l’option Optional LikeExcel as boolean.= False
Une idée. Par défaut Je propose = False
Comme ça on garde la symétrie sans avoir à ne changer l’option QUE si nécessaire.
 
Ouais, sauf qu'il n'y a pas en l'état de réelle symétrie.
Sans paramètre dédié:
t(5) -> t(1/5) => idem Excel
t(1/5) -> t(5/1) => pas idem Excel.

Faudrait-il que je fasse
LikeExcel = False
t(5) -> t(5/1) => pas idem Excel
t(1/5) -> t(5/1) => pas idem Excel.
LikeExcel = True
t(5) -> t(1/5) => idem Excel
t(1/5) -> t(5) => idem Excel.
 
En fait j'aime bien ce qui est actuellement codé: => retourne TOUJOURS une table à 2 dimensions.
t(5) -> t(1/5) => idem Excel
t(5) -> t(5/1) => pas idem Excel (sur option NoTranspose)
t(1/5) -> t(5/1) => pas idem Excel.

Je n'aime pas du tout mais en toute logique c'est parfaitement valide.
t(1/5) -> t(5) => idem Excel.
Parce qu'en général dans les traitements, passer de 2 dimensions à 1 dimension ça n'a pas d'utilité ni de sens pratique pour la valorisation des Ranges.
 
Par exemple:
Tu veux ajouter des lignes dans une colonne, tu dois manipuler une table de type t(1/5) car seule la 2ème dimension est "Resizeable".
Au moment où tu veux valoriser ta colonne tu veux t(1/5) -> t(5/1) et sûrement pas t(1/5) -> t(5) dont tu ne peux rien faire pour valoriser la colonne, car avec t(5) tu restes en ligne comme pour t(1/5).

Il faut juste que les commentaires. de la fonction précisent clairement cette différence.
 
Dernière édition:
- Navigue sans publicité
- Accède à Cléa, notre assistante IA experte Excel... et pas que...
- Profite de fonctionnalités exclusives
Ton soutien permet à Excel Downloads de rester 100% gratuit et de continuer à rassembler les passionnés d'Excel.
Je deviens Supporter XLD

Discussions similaires

Retour