[API] Tout sur la variable tableau / table mémoire (array)

Quoi ? Vous ne connaissez pas cette suite bureautique libre et gratuite. Elle vous permet de faire ce que vous faîtes avec MS-Office sans avoir à pirater.
Bidouille
Webmestre
Messages : 502
Enregistré le : 21 mai 2007 16:08

[API] Tout sur la variable tableau / table mémoire (array)

Messagepar Bidouille » 17 juil. 2015 14:36

Les variables de tableau (appelées en anglais array) permettent de stocker des valeurs.
Dans d'autres langages, on peut aussi les dénommer par table mémoire.
On les appelle comme cela car elles sont exactement représentées comme dans une feuille de calcul. L'accès se fait donc par un indice qui correspond à la ligne ou la colonne.

La vitesse d'exécution d'une variable tableau est beaucoup plus rapide que dans une feuille sous Calc.
Cela vient du fait que tout se passe en mémoire vive (RAM). Cela varie de la puissance de la machine mais on peut parler d'un facteur de 1 à 10.
Dès lors, faire des tris, du filtrage ou des recherches sera beaucoup plus rapide en passant par une variable tableau.


***

Bidouille
Webmestre
Messages : 502
Enregistré le : 21 mai 2007 16:08

Déclaration des tableaux

Messagepar Bidouille » 17 juil. 2015 15:01

Plusieurs méthodes possibles :

Code : Tout sélectionner

Dim oTableau(50) As String

L'instruction Dim permet de dimensionner en mémoire la variable oTableau de 51 chaînes.
Pourquoi 51 ? Parce que l'index démarre à zéro.
Si vous voulez un tableau de 50 lignes, il suffit de déclarer 49 en valeur.

On peut aussi caractériser la variable avec d'autres types de données.

Code : Tout sélectionner

Dim oVal(9) As Long
déclare un tableau de 10 entiers longs

Si vous ne passez aucun type, Basic déclarera votre tableau avec du Variant. C'est une variable passe-partout qui peut contenir n'importe quel type de donnée.

Simplification de déclaration
On peut aussi simplifier en "typant" la variable directement. Ainsi :

Code : Tout sélectionner

Dim oTableau$(50)
typera oTableau avec des chaînes (symbole $).

D'autres typages existent :
  • % pour typer en entier
  • & pour typer en entier long
  • @ pour typer en monétaire
  • etc
Reportez vous à la documentation du Basic pour plus d'information.
.

Bidouille
Webmestre
Messages : 502
Enregistré le : 21 mai 2007 16:08

Décalage de l'index d'un tableau

Messagepar Bidouille » 26 août 2015 11:19

Il est aussi possible d'influer sur l'index du tableau.
Cela peut s'avérer pratique pour rendre compatible certaines données dont l'accès à un chiffre précis est nécessaire.

Ainsi la syntaxe suivante :

Code : Tout sélectionner

Dim oMois(1 To 12) As String
permettra d'accéder plus simplement à un mois donné.

Code : Tout sélectionner

oMois(1) = "Janvier"
oMois(2) = "Février"
...
oMois(12) = "Décembre"

Les cas sont cependant peu nombreux, il est toujours préférable d'avoir un index à zéro.

L'option Base
Rappelons que par défaut, le premier élément d'un tableau est l'élément 0.
Mais avec la ligne Option Base 1, le premier élément par défaut devient l'élément 1

Cette option est fortement déconseillé si vous voulez rester pleinement compatible avec l'extérieur.

Bidouille
Webmestre
Messages : 502
Enregistré le : 21 mai 2007 16:08

Connaître les dimensions et parcourir

Messagepar Bidouille » 26 août 2015 11:35

Si vous tentez d'accéder à un élément du tableau qui n'existe pas, Basic vous renverra dans les cordes.
Un message "index out of bounds" se traduisant par un "index hors des limites" s'affichera.
Cela arrive souvent lorsque le tableau n'a pas été créé par vous et qu'il est renvoyé par un objet que vous interrogez.

Il faut donc connaître les dimensions du tableau avant d'en attaquer le contenu.
Deux instructions permettent de retourner l'index le plus petit et le plus grand.
LBound renvoie la valeur inférieure du tableau et UBound la valeur supérieure.

Ainsi, il est facile de parcourir un tableau pour le lire ou pour écrire dedans :

Code : Tout sélectionner

Sub ParcoursTableau
  Dim a(10)
  For i = LBound(a) To UBound(a)
    a(i) = i
  Next i
End Sub


Il est possible également de parcourir un tableau avec l'instruction Each ... In :

Code : Tout sélectionner

   oTab = Array(1,2,3)
   For Each elem In oTab
      Msgbox elem
   Next elem

Bidouille
Webmestre
Messages : 502
Enregistré le : 21 mai 2007 16:08

Retailler un tableau

Messagepar Bidouille » 26 août 2015 12:19

Un tableau peut être agrandie grâce à l'instruction Redim.
Cela peut être pratique si sa taille a été sous estimée.

Mais attention, car Redim vide le contenu du tableau.
Si vous voulez conserver les valeurs, ajouter l'option Preserve.

Petit exemple :

Code : Tout sélectionner

Sub RetailleTableau()
   ' Création du tableau avec 5 éléments
   Dim a(5)
   For i = LBound(a) To UBound(a)
      a(i) = i
   Next i
   ' Retaillons le tableau à 10 éléments
   ReDim Preserve a(1 To 10) ' anciennes valeurs préservées
   For i = 6 To UBound(a)
      a(i) = i
   Next i
End Sub

Faites l'expérience en enlevant l'instruction Preserve, le tableau sera alors vidé des 5 premiers éléments.

Bidouille
Webmestre
Messages : 502
Enregistré le : 21 mai 2007 16:08

Remplir un tableau

Messagepar Bidouille » 26 août 2015 12:26

Avec l'instruction Array, on peut rapidement remplir un tableau.

Ainsi :

Code : Tout sélectionner

a = Array(3, 4, 5, 6, 7, 8, 36, 10, 37, 38, 39, 14)
me donnera un tableau de 12 lignes dont l'index démarre à 0 et se termine à 11.

Autre exemple en reprenant notre tableau de mois pour le remplir avec Array :

Code : Tout sélectionner

Dim oMois(1 To 12) As String
oMois = Array("Jan.", "Fév.", "Mars", "Avr.", "Mai", _
    "Juin", "Jui.", "Août", "Sep.", "Oct.", "Nov.", "Déc.")

Bidouille
Webmestre
Messages : 502
Enregistré le : 21 mai 2007 16:08

Tableau plus complexe

Messagepar Bidouille » 30 déc. 2015 18:15

Il est possible de réaliser des tableaux multi-dimensionnels.
Pour reprendre notre comparaison avec une feuille du tableur, nous n'avions jusqu'à présent qu'une seule colonne.
Un tableau peut bien sûr avoir plusieurs colonnes et plusieurs lignes.

Exemple avec cette forme :
tab_2_dim.png
tab_2_dim.png (3.52 Kio) Vu 80607 fois

Retranscription en Basic :

Code : Tout sélectionner

Dim Client(0 To 1)
a = Array(1, 2, 3, 4, 5)
b = Array("Tom", "Max", "Jim", "Joe", "Bob")
Client(0) = a
Client(1) = b

Pour obtenir les données, on indique les coordonnées colonne/ligne :

Code : Tout sélectionner

msgbox Client(0)(2) 'Renvoie 3
msgbox Client(1)(2) 'Renvoie Jim


Ce principe est identique avec le module Base lorsque vous exécutez une requête SQL. Cette dernière vous renvoie un tableau du même genre.

Bidouille
Webmestre
Messages : 502
Enregistré le : 21 mai 2007 16:08

Tableau de tableaux

Messagepar Bidouille » 07 févr. 2016 15:01

Comme dans l'exemple précédent, vous pouvez également insérer des tableaux dans un tableau.
En déclarant le tableau principal comme "variable", les sous-tableaux sont imbriqués les uns à la suite des autres.

Code : Tout sélectionner

    Dim oTab as variant
    oTab = array( _
            array("Max", "Joe", "Mel"),_
            array("Lea", "Zoe", "Jim"),_
            array("Wil", "Ron", "Tom"),_
            array("Lou", "Bob", "Don"))

Pour récupérer une valeur :

Code : Tout sélectionner

    Msgbox oTab(0)(2) ' Mel
    Msgbox oTab(3)(1) ' Bob

Autre syntaxe possible en extrayant le sous-tableau :

Code : Tout sélectionner

    Dim oSsTab As Variant
    oSsTab = oTab(1)
    Msgbox oSsTab(1) ' Zoe

Pour ce type de tableaux imbriqués, il n'existe pas de déclaration directe. Il faut passer par une boucle pour déclarer les sous-tableaux avec l'instruction DimArray.
Ainsi pour notre exemple, nous aurons le code suivant :

Code : Tout sélectionner

Dim oTab(0 To 3) as variant
For i = 0 to 3
   oTab(i) = DimArray(2)
Next i



.

Bidouille
Webmestre
Messages : 502
Enregistré le : 21 mai 2007 16:08

Récupérer une sélection dans une feuille

Messagepar Bidouille » 11 mars 2016 15:53

Dans cette feuille, j'ai besoin de transférer le contenu sélectionné dans une variable :
_tab.png
_tab.png (24.99 Kio) Vu 80605 fois

Dans une macro, il est possible en une ligne de récupérer cette sélection :

Code : Tout sélectionner

oSelect = ThisComponent.CurrentSelection.Data()

La variable récupérée sera sous la forme d'un tableau indexé de 0 à 2 et représentant les 3 lignes.
Puis de 3 sous-tableaux indexé de 0 à 3 représentant cette fois, les 4 colonnes.
Nous en revenons donc à l'accès sous cette forme :

Code : Tout sélectionner

msgbox oSelect (0)(1) ' va afficher 21
msgbox oSelect (2)(0) ' va afficher 13

Bidouille
Webmestre
Messages : 502
Enregistré le : 21 mai 2007 16:08

Récupérer une plage dans une feuille

Messagepar Bidouille » 11 mars 2016 16:32

Sans sélection, la démarche consiste à récupérer les objets successivement :
Classeur > Feuille > Plage > Données
Ce qui nous donne :

Code : Tout sélectionner

oDoc = ThisComponent ' Le classeur
oFeuil = oDoc.Sheets(0) ' La 1ere feuille qui est indexée à 0
oPlage = oFeuil.getCellRangeByName("A1:D3")
oSelect = oPlage.Data

Le tableau oSelect se manipule de la même façon que précédemment.

NB : si les données sont sous forme de texte, il est préférable d'utiliser la propriété DataArray.

Bidouille
Webmestre
Messages : 502
Enregistré le : 21 mai 2007 16:08

Envoyer le contenu du tableau sur une feuille

Messagepar Bidouille » 11 mars 2016 16:38

On s'inspire du code précédent et on fait la manipulation sur une autre feuille du classeur :

Code : Tout sélectionner

oDoc = ThisComponent ' Le classeur
oFeuil = oDoc.Sheets(1) ' La 2e feuille
oPlage = oFeuil.getCellRangeByName("A1:D3")
oPlage.Data = oSelect

On voit qu'il est très simple de coller un tableau dès lors que la plage d'arrivée est dimensionnée correctement.

Bidouille
Webmestre
Messages : 502
Enregistré le : 21 mai 2007 16:08

Ne copier qu'une ligne sur deux

Messagepar Bidouille » 11 mars 2016 18:01

_tab.png
_tab.png (11.62 Kio) Vu 80605 fois

Code : Tout sélectionner

oDoc = ThisComponent ' Le classeur
oFeuil = oDoc.Sheets(0) ' La 1ere feuille qui est indexée à 0
oPlage = oFeuil.getCellRangeByName("A1:G5")
oTab = oPlage.Data()

oRes = array(oTab(0),oTab(2),oTab(4))

oPlage = oFeuil.getCellRangeByName("A12:G14")
oPlage.Data() = oRes()


Pour ce 2e exemple, nous avons un nombre de lignes beaucoup plus important :

Code : Tout sélectionner

sPlage = "A1:C33"
   
   oDoc = ThisComponent ' Le classeur
   oFeuil = oDoc.Sheets(0) ' La 1ere feuille qui est indexée à 0
   oPlage = oFeuil.getCellRangeByName(sPlage)
   oTab = oPlage.Data
   for i = LBound(oTab) To UBound(oTab)
      Redim Preserve oRes(0 To i)
      oRes(i) = oTab(j)
      j = j+2
      if j > UBound(oTab) then exit for
   Next i
   
   oFeuil = oDoc.Sheets(1) ' La 2e feuille
   i = UBound(oRes)
   j = UBound(oRes(i))
   oPlage = oFeuil.getCellRangeByPosition(0,0,j,i)
   oPlage.Data = oRes

On privilégiera cette fois, un getCellRangeByPosition pour déterminer la taille du nouveau tableau.
C'est beaucoup plus simple puisque l'on peut intégrer directement les informations de dimension pour la plage de destination.

Bidouille
Webmestre
Messages : 502
Enregistré le : 21 mai 2007 16:08

Transposition

Messagepar Bidouille » 15 mars 2016 11:42

La transposition de tableau est une opération courante qu'on appelle aussi matrice transposée.
Elle est obtenue en échangeant les lignes et les colonnes :
_tab.png
_tab.png (3.58 Kio) Vu 80604 fois


Le code suivant fait la transposition du tableau A1:C2 en A1:B3 :

Code : Tout sélectionner

   sPlage = "A1:C2"
   
   oDoc = ThisComponent ' Le classeur
   oFeuil = oDoc.Sheets(0) ' La 1ere feuille qui est indexée à 0
   oPlage = oFeuil.getCellRangeByName(sPlage)
   oTab = oPlage.Data
   ' Déclaration du tableau transposé
   m = UBound(oTab)
   n = UBound(oTab(0))
   Dim oRes(n)
   For i = 0 to n
      oRes(i) = dimArray(m)
   Next i
   ' Transposition
   For i = 0 to m
      For j = 0 to n
         oRes(j)(i) = oTab(i)(j)
      Next j
   Next i
   ' Affichage du tableau transposé
   oFeuil = oDoc.Sheets(1) ' La 2e feuille
   oPlage = oFeuil.getCellRangeByPosition(0,0,m,n)
   oPlage.Data = oRes

Bidouille
Webmestre
Messages : 502
Enregistré le : 21 mai 2007 16:08

Regroupement

Messagepar Bidouille » 15 mars 2016 18:10

Il arrive d'avoir à faire des regroupements sur une 1ere colonne :
_tab.png
_tab.png (7.52 Kio) Vu 80601 fois

Attention : le tableau doit être trié sur la 1ere colonne.

Code : Tout sélectionner

   sPlage = "A1:B9"
   
   oDoc = ThisComponent ' Le classeur
   oFeuil = oDoc.Sheets(0) ' La 1ere feuille qui est indexée à 0
   oPlage = oFeuil.getCellRangeByName(sPlage)
   oTab = oPlage.DataArray
   
   ' Déclaration du tableau de regroupement
   m = UBound(oTab) ' valeur maximum
   Dim oRgp(0 To m) as variant
   For l = 0 to m
      oRgp(l) = DimArray(1)
   Next l
   
   While i <= Ubound(oTab)
      oRgp(k)(0) = oTab(i)(0)
      For j = i to m
         if (oRgp(k)(0) = oTab(j)(0)) then
            oRgp(k)(1) = oRgp(k)(1) & oTab(j)(1) & " "
         else
            exit for
         endif
      Next
      k = k + 1
      i = j
   Wend
   Redim Preserve oRgp(0 To k-1) ' Réduction du tableau
   
   oFeuil = oDoc.Sheets(1) ' La 2e feuille
   i = UBound(oRgp)
   j = UBound(oRgp(i))
   oPlage = oFeuil.getCellRangeByPosition(0,0,j,i)
   oPlage.DataArray = oRgp

On crée au départ un tableau de sortie aussi grand que celui en entrée.
Une fois le regroupement fait, on le redimensionne avant de le réintégrer dans la feuille.

NB : on rappelle que les données texte doivent être gérées avec la propriété DataArray.

Bidouille
Webmestre
Messages : 502
Enregistré le : 21 mai 2007 16:08

Regroupement (II)

Messagepar Bidouille » 16 mars 2016 11:55

Cette fois, les données de la seconde colonne sont éclatées dans des cellules distinctes :
_tab.png
_tab.png (14.05 Kio) Vu 80599 fois

Code : Tout sélectionner

   sPlage = "A1:B12"
   
   oDoc = ThisComponent ' Le classeur
   oFeuil = oDoc.Sheets(0) ' La 1ere feuille qui est indexée à 0
   oPlage = oFeuil.getCellRangeByName(sPlage)
   oTab = oPlage.DataArray
   
   ' Déclaration du tableau de regroupement
   m = UBound(oTab) ' valeur maximum
   Dim oRgp(0 To m) as variant
   For o = 0 to m
      oRgp(o) = DimArray(m)
   Next o

   While i <= Ubound(oTab)
      l = 1
      oRgp(k)(0) = oTab(i)(0)
      ' Complete le sous-tableau à vide
      For j = 1 to m
         oRgp(k)(j) = ""
      Next j
      For j = i to m         
         if (oRgp(k)(0) = oTab(j)(0)) then
            oRgp(k)(l) = oTab(j)(1)
            l = l + 1
         else
            exit for
         endif
      Next
      k = k + 1
      i = j
   Wend
   Redim Preserve oRgp(0 To k-1)
   
   oFeuil = oDoc.Sheets(1) ' La 2e feuille
   i = UBound(oRgp)
   j = UBound(oRgp(i))
   oPlage = oFeuil.getCellRangeByPosition(0,0,j,i)
   oPlage.DataArray = oRgp


NB : laisser un tableau avec un contenu vide donne une erreur #N/D lors du transfert sur la feuille.


Retourner vers « OpenOffice »

Qui est en ligne

Utilisateurs parcourant ce forum : Aucun utilisateur enregistré et 108 invités