Pb de manipulation des tableaux dans un code VBA
Bonjour,
Plus habitué aux langages matlab ou R, j'ai un petit souci avec le code VBA dans lequel je débute.
Mon problème est simple: j'ai un fichier excel avec des données dans les colonnes de A à D, de la ligne 1 à la ligne n. Dans une fonction VBA, je souhaite qu'une variable tableau récupère les données de A2 jusqu'à An dans la première colonne, de B2 jusqu'à Bn dans la 2ème colonne et de D2 jusqu'à Dn dans la 3ème colonne. Les données de la colonne C ne sont donc pas récupérées.
Je pensais m'en sortir avec le code suivant:
Function TEST()
Dim TATAB()
TATAB = Union(Range("A2", Range("A2").End(xlDown)), Range("B2", Range("B2").End(xlDown)), Range("D2", Range("D2").End(xlDown))).Value
End Function
Mais dans ce cas, ma variable TATAB récupère les données des colonnes A et B mais pas de la colonne D. je ne comprends pas pourquoi. Quelqu'un accepterait-il de m'éclairer sur ce point?
Autre question: je peux éviter ce problème en parcourant simplement le tableau excel, sans créer de variable, mais j'ai cru comprendre au cours de mes recherches sur internet que c'était plus rapide de passer par une variable. Qu'en pensez-vous?
Merci d'avance,
Cordialement,
Adrien
PS. mon but final est de parcourir une table, si "Ai = critère 1" ET "Bi = critère 2" la fonction s'arrête de parcourir la table et retourne 1, sinon elle continue de parcourir la table. Si elle ne trouve ces 2 conditions validées pour aucune des lignes, elle retourne 0.
Bonjour,
Tout dépend de ce que tu souhaites faire...
Si tu codes une procédure Function, c'est que tu entends en récupérer le résultat (à partir d'une autre procédure).
Et ce qui différencie une Function d'une Sub, c'est qu'au minimum une fois lors de son exécution, le plus souvent à la fin, on a une ligne qui renvoie le résultat : NomFunction = Résultat.
Et on appelle la fonction pour récupérer le résultat (autre procédure) :
Sub Test()
Dim a
a = Mafonction()
'et on utilise a...
End SubSi je comprends ton souci, il serait simplement de tester les colonnes 1 et 2 de ta plage jusqu'à rencontrer des critères prédéfinies des valeurs sur la même ligne... Mais alors, que vient faire la 4e colonne ?
Cordialement.
Bonjour,
Merci de ton retour rapide.
J'ai proposé un exemple minimal avec une fonction qui ne retourne rien mais je suis intéressé par faire une fonction et non un sub (a priori).
J'ai essayé de simplifier mon explication mais du coup je crois que mon projet a perdu de son sens
Dans le détail: j'ai parlé de 4 colonne car je vais concatener les données de la colonne A et B, et les tester par rapport au critère 1, et tester la colonne D par rapport au critère 2. Mais je te propose de ne pas tenir compte de mon PS. dans le message précédent.
Mon problème reste essentiellement le même si on oublie la 4ème colonne et qu'on modifie mon exemple de code pour récupérer les données de la colonne A et de la colonne C sans récupérer les données de la colonne B. La variable résultante ne contient que les données de la colonne A.
Adrien
Ce qui importe, c'est le résultat à obtenir... On voit ensuite comment optimiser au mieux l'obtention de ce résultat...
Si tu veux une fonction qui va traiter ta plage de données, il est nécessaire de lui passer cette plage en argument.
Ensuite, tu peux effectivement accélérer l'exécution en récupérant les valeurs de la plage sous forme de tableau et tu travailles sur le tableau.
Enfin, comme tu veux utiliser la fonction en feuille de calcul, soit réaliser une fonction personnalisée, si tu souhaites que la fonction puisse se recalculer lors des recalculs automatiques, il faut introduire la ligne, après les déclarations de variables :
Application.Volatilece qui n'est d'ailleurs pas toujours souhaitable, et à l'inverse pour qu'elle ne se recalcule pas :
Application.Volatile FalseFunction TEST(Plg As Range) As Integer
Dim aa, i%, Crit1, Crit2
Crit1 = 'définition critère1
Crit2 = 'définition critère2
aa = Plg
For i = 1 To UBound(aa)
If aa(i, 1) & aa(i, 2) = Crit1 And aa(i,4) = Crit2 Then
TEST = 1: Exit For
End If
Next i
End FunctionLà tu récupères la plage passée à la fonction en l'affectant à une variable de type Variant, ce qui produit un tableau à deux dimensions de base 1. Tu parcours donc les lignes, première dimension du tableau, et tu testes la concaténation des éléments des 2 premières colonnes et l'élément de la 4e. Si la condition est vérifiée, tu renvoies le résultat. Tu n'as pas besoin de renvoyer un résultat en cas de non satisfaction de la condition, car ta fonction étant déclarée comme renvoyant un résultat de type Integer, elle renverra 0 par défaut.
Sur ta feuille : =TEST(A2:D5)
Cordialement.
bonjour
salut au passage MFerrand
avec Excel on peut faire ce qu'un Riste ou Pythoniste ne peut même pas rêver : une addition sans ligne de code
alors pour traiter une table et stopper sur condition, on peut le faire avec des colonnes de pointage. Sans code.
on ne "manipule" pas la table !
joins un fichier exemple de tes données et du résultat attendu
Je souhaite effectivement créer une fonction personnalisée. Merci pour le conseil application.volatile, je n'en avais pas encore entendu parlé.
Merci également pour ton code proposé. Mais je crois que j'ai mal exposé mon problème. Je vais essayer de préciser certains points:
- Tu as écrit:
si tu veux une fonction qui va traiter ta plage de données, il est nécessaire de lui passer cette plage en argument
La plage à regarder est fixe, je n'ai pas besoin de la passer à la fonction; mais peu importe, ce n'est pas le coeur de ma question.
- Nous avons discuté d'un exemple de tableau à 4 colonnes. Mais, si au lieu de 4 colonnes, le tableau en a 100; et seulement 3 colonnes nous intéressent pour la formule. Avec ton code, excel va manipuler une variable tableau avec 100 colonnes alors que seulement 3 sont utiles. J'imagine que ça ralentit les calculs. D'où ma question initiale, comment attribuer à la variable tableau (aa dans ton code), seulement quelques colonnes (pas forcément accolées) d'un tableau plus important? (en partant de la 2ème ligne et jusqu'à la dernière cellule remplie).
---
je vais joindre un fichier exemple plus complet
Merci encore à tous les 2 pour vos retour.
J'ai préparé un nouveau fichier d'exemple plus complet, mais qui ne fonctionne pas en raison du problème que j'essaye de résoudre.
Ma fonction prend comme argument le critère 1 à respecter (la concaténation de 'trial' et de 'meteo'). La plage et le critère 2 sont définis dans le code.
N'hésitez pas à me dire si vous pensez qu'il serait préférable de suivre une autre approche pour traiter plus efficacement ma problématique. Mais j'aimerais aussi (et peut-être surtout), comprendre pourquoi mon exemple ne fonctionne pas.
Merci d'avance.
(PS. je ne remets pas en question la puissance d'Excel et du VBA par mes commentaires. Je ne suis juste pas habitué à la façon de coder)
Tout dépend du traitement à faire...
Tu peux composer un tableau élément par élément, pour n'avoir que ceux qui t'intéressent...
Il y a quantité de méthodes possibles, et tu peux coder différentes méthodes pour comparer leur durée d'exécution et retenir la plus rapide...
Mais enfin, ça risque de prendre plus de temps : entre 1/20e de seconde et 2/10e de seconde, tu ne sentiras aucune différence, pourtant l'une est 4 fois plus rapide. Cela ne vaut la peine de s'y pencher que lorsqu'on atteint la seconde en durée. Tant que le déroulement est perçu comme instantané...
Cordialement.
Ok. MFerrand.
Si quelqu'un sait et veut bien m'expliquer pourquoi mon code ne fonctionne pas, je reste preneur.
Merci.
Comprends pas ce que tu fais ?
Si tu passes comme critère à la fonction la concaténation de A et L sur la ligne, ce critère sera forcément vérifié sur la ligne, il n'y a que la valeur de Q à vérifier, et uniquement sur la ligne, car en dupliquant ta fonction sur chaque ligne c'est que tu entends vérifier la ligne.
Tu affectes à TATAB les valeurs d'une plage multizones, il ne prendra que la première...
Ta variable n est tout à fait inutile, tu l'initialises avec une valeur qui ne va servir qu'une fois lors de la mémorisation de la limite de boucle, qui n'aurait pas pris plus de temps avec la valeur directement. Tu as le temps d'initialisation en plus !
Je crois qu'il te faut d'abord définir ce que tu veux obtenir de ta fonction :
- un résultat concernant la ligne ou un résultat concernant l'ensemble du tableau ?
- et si tableau, savoir si ce résultat est constitué d'une seule valeur ou d'un tableau de valeurs ?
re à vous
avec des SI() on mettrait...
mais on fait des trucs ultra-simples aussi
on ne parcourt pas la table au sens d'une procédure.