Récupérer le contenu d'une variable à partir de son nom
Bonjour à tous.
Un problème que je dois pas être le seul à n'avoir pas réussi à résoudre : dans une fonction vba, je définis et calcule plein de variables. En retour de cette fonction, j'aimerai bien avoir la valeur d'une de ces variables calculées.
En faisant simplifiant à l'extrême, cela donnerait le code suivant :
Function test(x1, x2, x3, sortie)
y1 = x1
y2 = 2 * x2
y3 = 3 * x3
Select Case sortie
Case "y1": test = y1
Case "y2": test = y2
Case "y3": test = y2
Case Else
End Select
End FunctionMais en réalité, il y a plus d'une centaine de variables calculées ... ce qui ferait un bloc select assez lourd et ingérable dès qu'une nouvelle variable est introduite dans la fonction.
L'idée serait de pouvoir faire passer le nom de la variable voulue dans le variable "sortie", (par exemple sortie="y2") et de l'envoyer dans la fonction. Ca donnerait :
Function test(x1, x2, x3, sortie)
y1 = x1
y2 = 2 * x2
y3 = 3 * x3
test = sortie '(c'est là que ça coince ... !o)
End FunctionQuelqu'un a déjà trouvé comment procéder ?
Un grand merci !
Bonjour,
En général ça ne se présente pas comme ça. Surtout quand il y a une grande quantité de variables :
On utilise alors des tableaux de valeurs et des indices.
Ça peut donner quelque chose comme ça :
Function test(x1, x2, x3, ind)
Dim tablo(100)
Select Case ind
Case 1: tablo(1) = x1
Case 2: tablo(2) = 2 * x2
Case 3: tablo(3) = 3 * x3
Case Else: tablo(0) = "beurk"
ind = 0
End Select
test = tablo(ind)
End Function
Sub galopin()
MsgBox test(2, 4, 7, 3)
End Sub...mais ce n'est qu'un exemple comme toute macro ça doit être réglé avec précision !
A+
Merci de la réponse rapide Galopin !
effectivement, les tableaux seraient une façon de procéder.
Malheureusement, pour rendre le code compréhensible (surtout pour moi !), avoir des variables ayant un nom explicite est utile.
Voici un extrait du code un peu plus complet que l'exemple simplissime de mon post initial (le vrai code calcule plus de 100 variables à partir de 7 variables d'entrée). Ce code fait appel à d'autres fonctions (exemple : Enthalpy, Temperature, ...)
Pour moi, avoir des noms de variables clairs est utile : t1 est la température au point 1, p6 la pression au point 6 etc ...
Function simul_cycle_1(Phi0, t0, sc, p_gc, t_sgc, Nu_Is_Cp, Effi_IHX, sortie)
[ ...]
p3 = p_gc
t3 = t_sgc
h3 = Enthalpy(p3, t3)
p6 = Pressure(t0 + sc)
t6 = t0 + sc
h6 = Enthalpy(p6, t6 + 0.0001)
p1 = Pressure( t0)
h1 = h6 + Effi_IHX * (Enthalpy(p1, t3) - h6)
t1 = Temperature(p1, h1)
s1 = Entropy(p1, h1)
h4 = h3 - (h1 - h6)
p4 = p3
t4 = Temperature(p4, h4)
[ ... ]Pour récupérer la valeur de la variable h4 (par exemple), il serait commode de pouvoir dire : sortie = "h4", mais malheureusement, ce se fait pas aussi simplement...
Vous auriez une idée de la faisabilité et de comment procéder ?
Encore merci.
Il faut faire un table de conversion sur le modèle suivant :
Function simul_cycle_1(Phi0, t0, sc, p_gc, t_sgc, Nu_Is_Cp, Effi_IHX, sortie$)
Dim Tablo, i%
1 Tablo = Split("h1 h3 h4 h6 p1 p3" & _
" p4 p6 s1 t1 t3" & _
" t4 t6")
2 For i = LBound(Tablo) To UBound(Tablo)
3 If Tablo(i) = sortie Then Exit For
4 Next
5 Tablo(0) = Tablo(3) + Effi_IHX * (Enthalpy(Tablo(4), Tablo(10)) - Tablo(3))
6 Tablo(1) = Enthalpy(Tablo(5), Tablo(10))
7 Tablo(2) = Tablo(1) - (Tablo(0) - Tablo(3))
8 Tablo(3) = Enthalpy(Tablo(7), Tablo(12) + 0.0001)
9 Tablo(4) = Pressure(t0)
10 Tablo(5) = p_gc
11 Tablo(6) = Tablo(5)
12 Tablo(7) = Pressure(t0 + sc)
13 Tablo(8) = Entropy(Tablo(4), Tablo(0))
14 Tablo(9) = Temperature(Tablo(4), Tablo(0))
15 Tablo(10) = t_sgc
16 Tablo(11) = Temperature(Tablo(6), Tablo(2))
17 Tablo(12) = t0 + sc
18 simul_cycle_1 = Tablo(i)
End Function
Sub test()
MsgBox simul_cycle_1(1, 2, 3, 4, 5, 6, 7, "p4")
End SubNota : Le code ne fonctionne pas car i y a les fonctions que je connais pas (Enthalpy, Pressure, temperature...
Tablo contient 13 valeurs indexées de 0 à 12
Pour une raison de facilité de lecture les 6 premières (de 0 à 5 sont lignes 1
ensuite en dessous les 5 suivantes de 6 à 10
On peut continuer ainsi avec une centaine de variable et se repérer assez facilement en continuant à en mettre 5 par lignes
Attention aux espaces dans le Split : ce sont eux qui servent de séparateur !
A+
A mon avis la table de conversion devrait à elle seule faire l'objet d'une fonction personnalisée...
Une autre possibilité basé sur un Dico (redoutable au niveau rapidité).
Toujours pareil : Je n'ai pas pu tester car je n'ai pas les fonctions perso...
Function simul_cycle_1(Phi0, t0, sc, p_gc, t_sgc, Nu_Is_Cp, Effi_IHX, sortie)
Dim a, i%, D, S$
Set D = CreateObject("Scripting.Dictionary")
S = "h1 h3 h4 h6 p1 p3 p4 p6 s1 t1 t3 t4 t6"
a = Split(S)
For i = LBound(a) To UBound(a)
D.Add a(i), ""
Next
D("p3") = p_gc
D("t3") = t_sgc
D("h3") = Enthalpy(D("p3"), D("t3"))
D("p6") = Pressure(t0 + sc)
D("t6") = t0 + sc
D("h6") = Enthalpy(D("p6"), D("t6") + 0.0001)
D("p1") = Pressure(t0)
D("h1") = D("h6") + Effi_IHX * (Enthalpy(D("p1"), D("t3")) - D("h6"))
D("t1") = Temperature(D("p1"), D("h1"))
D("s1") = Entropy(D("p1"), D("h1"))
D("h4") = D("h3") - (D("h1") - D("h6"))
D("p4") = D("p3")
D("t4") = Temperature(D("p4"), D("h4"))
simul_cycle_1 = D(sortie)
End Function
Sub test()
MsgBox simul_cycle_1(1, 2, 3, 4, 5, 6, 7, "p4")
End SubBonjour,
autre possibilité en passant par une énumération :
Enum variables
y1
y2
y3
End Enum
Function test(x1, x2, x3, sortie)
Dim v(0 To 2)
v(y1) = x1
v(y2) = 2 * x2
v(y3) = 3 * x3
test = v(sortie)
End Function
Sub test2()
Dim a
a = test(1, 2, 3, y2)
End Suble fait de ne pas donner de valeur lors de l'énumération fait un remplissage automatique à partir de 0, qu'on se sert pour indexer un tableau (y1=0, y2=1, etc).
eric
PS : oublié de dire que ça te permet de bénéficier aussi de l'auto-complétion
Par exemple tu nommes toutes tes variables de t° en les commençant par "t_"
En saisie tu démarres a = test(1, 2, 3, t_
avec Ctrl+espace tu as la liste de tes variables de température déclarées dans l'enum
Edit : petite amélioration pour ne pas à avoir le compte des variables à tenir, et que les tableaux s'adaptent automatiquement à leur nombre :
Enum variables
[_First] = 0
y1
y2
y3
[_Last]
End Enum
Function test(x1, x2, x3, sortie)
Dim v(variables.[_First] + 1 To variables.[_Last] - 1)
v(y1) = x1
v(y2) = 2 * x2
v(y3) = 3 * x3
test = v(sortie)
End Function
Sub test2()
Dim a
a = test(1, 2, 3, y2)
End SubBonjour,
et merci de vos réponses.
Trop fort galopin01 : je ne connaissais pas le coup du Dictionary. Ca devrait très bien marcher dans mon cas.
Un grand merci à Eriiic pour son astuce : je ne connaissais pas non plus la ruse des [_First] et [_Last]
... on en apprend tous les jours avec Vba, qui décidément est plein de ressources !
Je modifie mon code en conséquence et ne manquerai pas de vous tenir au courant.
Bien à vous.
JaGu.
C'est vrai qu'on ne pense pas forcément à Enum qui pour le coup est certainement le plus commode dans ton cas : ça dispense de tous ces guillemets dans le code...
Merci à Eric de nous en avoir rappelé toutes les subtilités.
A+
Bonjour Galopin et Eriiic
Après avoir un peu tout testé hier, il me semble que le meilleure solution est de passer par un tableau à 2 dimensions.
la première dimension est le nom de la variable (p comme pression, t comme température, h comme enthalpie, etc ...)
la seconde est l'indice du point (1, 2, etc ...)
Donc du coup X(p,6) est facilement lisible : c'est la pression au point 6.
Le fonction Enum marche très bien pour définir les indices de la première dimension.
Par contre, si je demande "p" comme variable de sortie, il faut traduire que "p" = 1 pour pouvoir récupérer le bon indice.
Donc j'ai été amené à procéder comme suit :
Function simul_cycle_base(fluide$, Phi0, t0, sc, p_gc, t_sgc, Nu_Is_Cp, Effi_IHX, Param_S, Point_S)
p = 1: t = 2: h = 3: v = 4: q = 5: S = 6: m = 7: w = 8: cop = 9
Select Case LCase(Param_S)
Case "p": Param_S = 1
Case "t": Param_S = 2
Case "h": Param_S = 3
Case "v": Param_S = 4
Case "q": Param_S = 5
Case "s": Param_S = 6
Case "m": Param_S = 7
Case "w": Param_S = 8
Case "cop": Param_S = 9
End Select
ReDim x(10, 200)
x(p, 3) = p_gc
x(t, 3) = t_sgc
If t_sgc >= Temperature(fluide$, "crit", "c") Then
x(p, 3) = p_gc
Else
x(p, 3) = Pressure(fluide$, "tliq", "c", t_sgc + 0.0001)
End If
x(h, 3) = Enthalpy(fluide$, "pt", "c", x(p, 3), x(t, 3))
x(p, 6) = Pressure(fluide$, "tvap", "c", t0)
x(t, 6) = t0 + sc
x(h, 6) = Enthalpy(fluide$, "pt", "c", x(p, 6), x(t, 6) + 0.0001)
x(p, 1) = x(p, 6)
x(h, 1) = x(h, 6) + Effi_IHX * (Enthalpy(fluide$, "pt", "c", x(p, 1), x(t, 3)) - x(h, 6))
x(t, 1) = Temperature(fluide$, "ph", "c", x(p, 1), x(h, 1))
x(S, 1) = Entropy(fluide$, "ph", "c", x(p, 1), x(h, 1))
x(v, 1) = Volume(fluide$, "ph", "c", x(p, 1), x(h, 1))
x(h, 4) = x(h, 3) - (x(h, 1) - x(h, 6))
x(p, 4) = x(p, 3)
x(t, 4) = Temperature(fluide$, "ph", "c", x(p, 4), x(h, 4)
' etc ... (plus de 100 lignes de code)
'et avant de sortir de la fonction :
simul_cycle_base = x(Param_S, Point_S)
end functionVoilà. C'est un peu lourd, mais ça fonctionne bien.
Un grand merci encore à vous deux et un coup de chapeau à vos excellentes connaissances Excelliennes !
Bonjour,
Je ne vois pas pourquoi en faisant un enum avec p = 1: t = 2: h = 3: v = 4: q = 5: S = 6: m = 7: w = 8: cop = 9 tu n'aurais pas p=1 que ce soit en utilisation de constantes dans la fonction, ou bien en passage de paramètre.
Si tu appelles ta fonction avec p pour Param_S et bien Param_S =1 dans ta fonction (?!?)
Non pas que je veuille te faire changer mais c'est pour comprendre s'il y a une limitation inconnue. C'est à quel point que ça bloque ?
Si tu pouvais faire le test en mettant en commentaire tes 13 premières lignes et voir ce que vaut Param_S au moment de l'appel de simul_cycle_base = x(Param_S, Point_S), et au début de cette dernière fonction.
Ou alors c'est que tu appelles simul_cycle_base() depuis la feuille et là p n'est pas connu si tu ne l'as pas définis dans les noms (?)
eric
Bonjour Eric,
Ce serait une bonne idée, mais le paramètre de sortie que je passe dans la fonction, c'est "p" ou "cop" ou encore "whp". Et passer les noms en clair (p, ou cop, ou whp etc ...), c'est plus facile à faire que de se rappeler que si je veux p, je dois passer 1, que si je veux whp, je dois passer 13, etc ... J'en aurai une trentaine à me rappeler, ce qui est difficile pour ma tête de linotte !
exemple : il est facile de voir que X(whp,25) représente la valeur de la variable whp au point 25, ce qui est plus facile à lire et à comprendre que X(13,25) ... à moins de se rappeler que 13 est l'indice correspondant à la variable whp.
Du coup, ça facilite grandement l'écriture du code et son débogage !
Pour info, la fonction est appelée depuis une feuille de calcul, le retour de la fonction étant mis dans le cellule appelante.
exemple :
si dans la cellule C4 je mets
simul_cycle_base($B$2, $B3, $B4, $B5, $B6, "whp", 25)
j'aurai la valeur de whp au point n°25 dans cette cellule, valeur qui dépend du contenu des cellules B2 .. B6
C'est vrai que l'idée de nommer les cellules est bonne, mais malheureusement, les paramètres d'entrée passés à la fonction ne sont pas toujours au même endroit (des fois, c'est par exemple $B$2, d'autres fois Q64 etc ...).
Il ne s'agit pas de nommer des cellules mais de créer un nom whp (= 13)
Ainsi whp serait connu des feuilles et de vba via l'enum.
Et partout tu aurais pu saisir whp au lieu de "whp"
Mais bon, si ça te va comme ça...