Précédent   Forum des professionnels en informatique > Logiciels > Microsoft Office > Excel > Macros et VBA Excel
Macros et VBA Excel Vos questions relatives aux macros Excel, à l'utilisation de VBA et à l'automatisation de vos classeurs Excel.
Partagez cette discussion sur d'autres réseaux sociaux : Viadeo Twitter Google Facebook Digg Delicious MySpace Yahoo
Réponse Proposer ce sujet en actualité
 
Outils de la discussion
Publicité
'
Vieux 19/08/2011, 19h24   #1
Futur Membre du Club
 
Pierre Bernier
Inscription : mai 2010
Messages : 41
Détails du profil
Informations personnelles :
Nom : Pierre Bernier

Informations forums :
Inscription : mai 2010
Messages : 41
Points : 19
Points : 19
Par défaut Prendre un vecteur 1D à partir d'un tableau 2D

Bonjour,

j'ai un tableau 2D de 15x2 dans une variable et je voudrais sélectionner les 15 valeurs de la première colonne sans devoir faire une boucle for. Est-ce possible?

Ex : vecteur1d=tableau2d(:,1)

Merci!
hbc87 est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 19/08/2011, 21h24   #2
Expert Confirmé Sénior
 
Avatar de jfontaine
 
Homme Jérôme FONTAINE
Contrôleur de Gestion
Inscription : juin 2006
Messages : 3 885
Détails du profil
Informations personnelles :
Nom : Homme Jérôme FONTAINE
Âge : 38
Localisation : France, Sarthe (Pays de la Loire)

Informations professionnelles :
Activité : Contrôleur de Gestion

Informations forums :
Inscription : juin 2006
Messages : 3 885
Points : 7 151
Points : 7 151
Bonjour,

Je trouve qu'une boucle for est plus "propre" mais pour répondre à ta question tu peux utiliser une plage de cellule

Code :
1
2
3
4
5
6
7
8
 
Dim vecteur1d() As Variant
 
'Copie de la variable tableau dans un onglet
Sheets("Feuil1").Range(Cells(1, 1), Cells(UBound(tableau2d, 1) + 1, UBound(tableau2d, 2) + 1)) = tableau2d
 
'Copie des données de la première colonne dans la variable à une dimension
vecteur1d= Sheets("Feuil1").Range(Cells(1, 1), Cells(UBound(tableau2d, 1) + 1, 1))
__________________
Jérôme

Citation:
"Ils ne savaient pas que c'était impossible, alors ils l'ont fait" - Marc Twain
Si la réponse répond à votre besoin, votre vote nous encouragera.
Dans le cas ou la réponse mérite, à vos yeux, un , nous faire partager la raison de ce vote, pourrait nous permettre de nous améliorer.
jfontaine est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 19/08/2011, 23h03   #3
Membre éclairé
 
Inscription : juillet 2011
Messages : 141
Détails du profil
Informations forums :
Inscription : juillet 2011
Messages : 141
Points : 382
Points : 382
Par défaut Extraire une colonne d'un tableau 2D pour écrire sur la feuille Excel

A la ligne 5 précédente, comme tableau2d a deux dimensions -- 15 rangées sur 2 colonnes --, l'affectation proposée a de forte chance de modifier à la fois les colonnes A & B. Hors on souhaite extraire la première colonne de tableau2d sans boucle For Next.

Cela sera montré au chapitre 2 par une façon que d'aucuns trouveront un tout petit peu inhabituel grâce à l'instruction peu connue LSet pour extraire la première colonne du tableau 2D sans boucles apparentes.

1. Ecrire un vecteur 1D dans une portion de colonne de la feuille

Au final on aboutira à l'affectation 2D vers 1D demandée, les boucles For Next intermédiaires ne servant qu'à lire le tableau 2D ou modifier ses éléments mais ne sont pas utilisées pour la lecture ou l'écriture sur la feuille. L'utilisation de l'expression "sélectionner les 15 valeurs de la première colonne" a pu faire penser qu'il s'agissait d'une écriture du tableau2d vers la feuille Excel.

Code :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
Option Explicit ' Lecture / écriture d'une portion de colonne via un vecteur
' ============================ Description de la feuille
Public Const rowDataStart = 1               ' Première rangée des données
Public Const rowDataEnd = rowDataStart + 14 ' Dernière rangée des données
 
Public Const colDataFirst = 1               ' Première colonne des données
Public Const colDataLast = colDataFirst + 1 ' Dernière colonne des données
 
Const patcherColA = 1, patcherColB = 10     ' Modificateur de colonnes A et B
 
Const colVar = 1 ' Le variant de lecture de la colonne A n'a qu'une colonne
Type VectorType
    ArrTab1D(rowDataStart To rowDataEnd) As Integer                   ' Vrai vecteur 1D
End Type
Type VectorCellType
    ArrTab2D(rowDataStart To rowDataEnd, colVar To colVar) As Integer ' Faux vecteur 1D
End Type
 
Type ArrayDoubleColType
    Col1 As VectorCellType  ' Faux vecteur 1D de la première colonne
    CoL2 As VectorCellType  ' Faux vecteur 1D de la seconde colonne
End Type
Type Array2ColType          ' Vrai tableau 2D
    ArrCol2D(rowDataStart To rowDataEnd, colDataFirst To colDataLast) As Integer
End Type
 
Sub Vecteur1DFromAndToCells()
Dim vector1D As VectorType, vectorCell As VectorCellType
Dim indRow As Integer, rngVect As Range, varVector As Variant
 
    Set rngVect = Range(Cells(rowDataStart, colDataFirst), Cells(rowDataEnd, colDataFirst))
    varVector = rngVect.Value     ' Lit en une seule fois la colonne A dans le Variant
 
    For indRow = rowDataStart To rowDataEnd ' Modifie le vecteur en incrémentant chaque élément.
        vectorCell.ArrTab2D(indRow, colVar) = varVector(indRow, colVar) + patcherColA
    Next
    rngVect = vectorCell.ArrTab2D ' Ecrit le vecteur en une seule fois en colonne A
'    rngVect = varVector          ' est aussi possible si on veut rester avec le Variant
 
    LSet vector1D = vectorCell    ' Copie vecteur 2D vers 1 D
    With vector1D
        For indRow = rowDataStart To rowDataEnd ' Modifie le vecteur 1D
            .ArrTab1D(indRow) = .ArrTab1D(indRow) + patcherColB ' élément par élément.
        Next
    End With
    LSet vectorCell = vector1D    ' Copie vecteur 1D vers 2D
 
    Set rngVect = Range(Cells(rowDataStart, colDataLast), Cells(rowDataEnd, colDataLast))
    rngVect = vectorCell.ArrTab2D ' Ecrit le vecteur "1D" en une seule fois en colonne B
End Sub
 
Sub Array2DFromAndToCells()
Dim rngArr As Range, array2Col As Array2ColType, arrayDouble As ArrayDoubleColType
Dim indRow As Integer, rngVect As Range, varVector As Variant, vectorCell As VectorCellType
 
    Set rngArr = Range(Cells(rowDataStart, colDataFirst), Cells(rowDataEnd, colDataLast))
    varVector = rngArr.Value     ' Lit en une seule fois les colonnes A & B dans le Variant
 
    With array2Col
        For indRow = rowDataStart To rowDataEnd ' Copie Variant vers tableau 2D
            .ArrCol2D(indRow, colDataFirst) = varVector(indRow, colDataFirst)
            .ArrCol2D(indRow, colDataLast) = varVector(indRow, colDataLast) - patcherColA - patcherColB
        Next
    End With
    LSet arrayDouble = array2Col        ' Copie le tableau 2D
    LSet vectorCell = arrayDouble.CoL2  ' Copie uniquement la seconde colonne
 
    Set rngVect = Range(Cells(rowDataStart, colDataLast), Cells(rowDataEnd, colDataLast))
    rngVect = vectorCell.ArrTab2D       ' Ecrit le vecteur "1D" en une seule fois en colonne B
 
    LSet vectorCell = arrayDouble.Col1  ' Ne copie que la première colonne
    With vectorCell
        For indRow = rowDataStart To rowDataEnd ' Restore la valeur initiale
            .ArrTab2D(indRow, colVar) = vectorCell.ArrTab2D(indRow, colVar) - patcherColA
        Next
        Set rngVect = Range(Cells(rowDataStart, colDataFirst), Cells(rowDataEnd, colDataFirst))
        rngVect = .ArrTab2D             ' Ecrit le vecteur en une seule fois en colonne A
    End With
End Sub
Sur la feuille de A1 à A15, on a mis les nombres de 1 à 15. Idem de B1 à B15

Dans la fenêtre d'Exécution immédiate (Ctrl+G) du VBE d'Excel, copier-coller et valider par ENTER :
Code :
Vecteur1DFromAndToCells
Sur la feuille, les nombres ont été incrémentés de patcherColA = 1 en colonne A et de patcherColB = 10 en colonne B.

On lit dans un Variant la colonne A. Une fois le variant modifié, l'écriture est réalisée en une seule opération. Plutôt qu'un variant on peut également utiliser un faux vecteur 1D dont la seconde dimension est toujours colVar = 1 :
Code :
1
2
3
4
    LSet vector1D = vectorCell    ' Copie vecteur 2D vers 1 D
 ' Modifier vector1D dans une boucle For Next
    LSet vectorCell = vector1D    ' Copie vecteur 1D vers 2D
    rngVect = vectorCell.ArrTab2D ' Ecrit le vecteur "1D" en une seule fois en colonne B
2. Extraire un vecteur 1D d'un tableau 2D sans For Next

On utilise l'instruction LSet pour séparer la première colonne de la seconde d'un tableau 2D sans boucle For Next.

Code :
1
2
3
4
5
6
    LSet arrayDouble = array2Col        ' Copie le tableau 2D 
    LSet vectorCell = arrayDouble.Col1  ' Ne copie que la première colonne
    With vectorCell
        Set rngVect = Range(Cells(rowDataStart, colDataFirst), Cells(rowDataEnd, colDataFirst))
        rngVect = .ArrTab2D             ' Ecrit le vecteur en une seule fois en colonne A
    End With
Dans la fenêtre d'Exécution immédiate (Ctrl+G) du VBE d'Excel, copier-coller et valider par ENTER :
Sur la feuille, les nombres ont été restaurés à leurs valeurs initiales 1 à 15 en colonne A et B mais en deux étapes bien distinctes à suivre en pas à pas dans le débogueur pour démontrer l'affectation de chaque vecteur individuellement par colonne.

3. Performance For Next 2D -> 1D vs. double LSet

Vérifions la performance du double LSet par rapport à extraire la première colonne du tableau 2D 15 rangées * 2 colonnes par une boucle For Next classique.

Code :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
Sub PerfForNext_LSet()
Const nbrIterationPerf = 100000000
Dim tStart As Double, tEnd As Double, indPerf As Long
Dim arr2D(rowDataStart To rowDataEnd, colDataFirst To colDataLast) As Integer
Dim arr1D(rowDataStart To rowDataEnd) As Integer, vector1D As VectorType
Dim array2Col As Array2ColType, arrayDouble As ArrayDoubleColType
Dim indRow As Integer, rngData As Range, varVector As Variant
 
    Set rngData = Range(Cells(rowDataStart, colDataFirst), Cells(rowDataEnd, colDataLast))
    varVector = rngData.Value     ' Lit en une seule fois les colonnes A & B dans le Variant
 
    With array2Col
        For indRow = rowDataStart To rowDataEnd ' Copie Variant vers tableau 2D
            array2Col.ArrCol2D(indRow, colDataFirst) = varVector(indRow, colDataFirst)
            array2Col.ArrCol2D(indRow, colDataLast) = varVector(indRow, colDataLast)
            arr2D(indRow, colDataFirst) = varVector(indRow, colDataFirst)
            arr2D(indRow, colDataLast) = varVector(indRow, colDataLast)
        Next
    End With
    tStart = Time
    For indPerf = 1 To nbrIterationPerf
        For indRow = rowDataStart To rowDataEnd: arr1D(indRow) = arr2D(indRow, colDataFirst): Next
    Next
    tEnd = Time
    Debug.Print "Copie élément par élément de la 1ere colonne en : " + Format(tEnd - tStart, "HH:MM:SS")
    tStart = Time
    For indPerf = 1 To nbrIterationPerf
        LSet arrayDouble = array2Col        ' Copie le tableau 2D
        LSet vector1D = arrayDouble.Col1    ' Copie uniquement la première colonne
    Next
    tEnd = Time
    Debug.Print "Copie de la 1ere colonne via deux LSet en       : " + Format(tEnd - tStart, "HH:MM:SS")
    Stop
End Sub
Dans la fenêtre d'Exécution immédiate (Ctrl+G) du VBE d'Excel, copier-coller et valider par ENTER :
Code :
1
2
Copie élément par élément de la 1ere colonne en : 00:00:59
Copie de la 1ere colonne via deux LSet en       : 00:00:07
Cela dépend du type des éléments du tableau 2D et de ses dimensions.
Le LSet apporte un gain ! Même s'il faut relativiser ce gain en considérant le nombre d'itérations 100000000 pour faire apparaître une différence de performance.

Le programme de mesure de la performance s'est arrêté sur le Stop avant End Sub.
Dans la fenêtre d'Exécution immédiate :
Code :
? arr2D(rowDataEnd, colDataFirst) & " = " & arr1D(rowDataEnd) & " = " & vector1D.ArrTab1D(rowDataEnd)
15 = 15 = 15
___________

Si la discussion est résolue, vous pouvez cliquer sur le bouton

En bas de ce message s'il vous a apporté des éléments de réponse pertinents, pensez également à voter en cliquant sur le bouton vert ci-dessous.
MattChess est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 21/08/2011, 11h32   #4
Rédacteur
 
Avatar de Ormonth
 
Homme Didier GONARD
Formateur Développeur Office - indépendant
Inscription : février 2008
Messages : 2 353
Détails du profil
Informations personnelles :
Nom : Homme Didier GONARD
Localisation : France, Loire Atlantique (Pays de la Loire)

Informations professionnelles :
Activité : Formateur Développeur Office - indépendant

Informations forums :
Inscription : février 2008
Messages : 2 353
Points : 4 682
Points : 4 682
Citation:
Envoyé par hbc87 Voir le message
Bonjour,

j'ai un tableau 2D de 15x2 dans une variable et je voudrais sélectionner les 15 valeurs de la première colonne sans devoir faire une boucle for. Est-ce possible?
Bonjour,

la vraie question serait : est-ce raisonnable ?

Alourdir une appli par une usine à Gaz, est-ce vraiment le but ?

Surtout si on considère le but final d'un code (hors son bon fonctionnement qui est de rigueur) : légèreté, lisibilité, portabilité, maintenance.

Citation:
Envoyé par jfontaine
Code :
1
2
'Copie des données de la première colonne dans la variable à une dimension
vecteur1d= Sheets("Feuil1").Range(Cells(1, 1), Cells(UBound(tableau2d, 1) + 1, 1))
as-tu vérifié le nombre de dimensions de ta variable dans le fenêtre Variables locales de l'éditeur VBE ou par ce biais ?
http://silkyroad.developpez.com/vba/tableaux/#LXIV-E

voir ici, sinon : http://didier-gonard.developpez.com/...vba/#LVIII-C-2

cordialement,

Didier
__________________
Didier Gonard

Ps :
Pour noter positivement ou négativement un post, vous pouvez cliquer sur les pouces en bas à droite !
Tutoriels : Voir la liste de mes tutoriels et mon site pro sur ma Page DVP
N'oubliez pas de mettre : ..quand c'est le cas !
Ormonth est actuellement connecté   Envoyer un message privé Réponse avec citation 00
Vieux 21/08/2011, 12h19   #5
Membre éclairé
 
Inscription : mai 2006
Messages : 335
Détails du profil
Informations personnelles :
Localisation : France

Informations forums :
Inscription : mai 2006
Messages : 335
Points : 326
Points : 326
Bonjour à tous

Nous ne connaissons pas le but final de cette "manipulation", mais pour ma part, je ferai tout simplement 2 tableaux distincts .

Eric
edelweisseric est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 22/08/2011, 16h11   #6
Futur Membre du Club
 
Pierre Bernier
Inscription : mai 2010
Messages : 41
Détails du profil
Informations personnelles :
Nom : Pierre Bernier

Informations forums :
Inscription : mai 2010
Messages : 41
Points : 19
Points : 19
Bonjour,

j'aurais due préciser un peu plus, j'ai un tableau 2D de 15x2 dans une variable suite à des calculs faits dans excel. Le but était d'extraire les noms des colonnes du tableau (qui n'ont aucun lien avec les noms des colonnes excel pour ensuite les envoyer dans l'axe X d'un histogramme.

Dans le langage matlab c'est possible simplement avec la commande variable2=variable1(15, : ).

Peut-être que VBA n'a pas été conçu de la même manière...
hbc87 est déconnecté   Envoyer un message privé Réponse avec citation 00
Réponse Proposer ce sujet en actualité
Outils de la discussion



Fuseau horaire GMT +2. Il est actuellement 11h31.


 
 
 
 
Partenaires

Hébergement Web