Parametri di una Function
Hai un problema con Excel? 
Parametri di una Function
di vmontal data: 27/03/2014 10:34:25
Save a tutti,
ho la necessità di scrivere una Function a cui devo passare oltre a dei valori anche l'Operatore di confronto (scusate l'italiano sporco) che devo svolgere;esempio
Calcola(Valore1 as Integer, Valore2 as Integer, Operatore as String) as Integer
IF Valore1 & operatore & Valore2 Then
calcola= Valore1
Else
Calcola= Valore2
Endif
End function
In cui Operatore può Essere ">";"<";"=";">=";"<="
Scritta così ovviamente non funziona e mi restituisce l'errore run-time "424" - Necessario Oggetto;
Qualcuno riesce a darmi dei suggerimenti?
di Vecchio Frac data: 27/03/2014 11:17:45
1) Puoi passare alla Function l'operatore che desideri sotto forma di stringa e poi valutare mediante Select Case ogni caso possibile.
Esempio:
private function Calcola(Valore1 as Integer, Valore2 as Integer, Operatore as String) as Integer
select case operatore
case "<", "=", "<="
if valore1 < valore2 then calcola = valore1
case ">", ">="
if valore2 > valore1 then calcola = valore2
end select
End function
2) Puoi usare Iif:
Private Function Calcola(Valore1 As Integer, Valore2 As Integer, Operatore As String) As Integer
Calcola = IIf(Valore1 <= Valore2, Valore1, Valore2)
End Function
ma anche senza inserirlo in una Function va benisismo:
calcola = IIf(valore1 <= valore2, valore1, valore2)
3) Se non servono i valori di ritorno puoi usare Evaluate per stabilire se la condizione è soddisfatta in funzione dell'operatore passato (restituisce -1 per True, 0 per False):
private function Calcola(Valore1 as Integer, Valore2 as Integer, Operatore as String) as Integer
calcola = Evaluate(valore1 & " " & operatore & " " & valore2)
End function
di Vecchio Frac data: 27/03/2014 11:19:53
Edit.
Nel caso 2 inserito in una Function, passare l'Operatore è ininfluente visto che non lo utilizzo.
Private Function Calcola(Valore1 As Integer, Valore2 As Integer) As Integer
Calcola = IIf(Valore1 <= Valore2, Valore1, Valore2)
End Function
di vmontal data: 27/03/2014 11:38:46
Ottimi Spunti di lavoro; Grazie davvero!
La soluzione con Evaluate mi sembrava la più pulita, ma mi accorgo che se uso delle date come valori il confronto non funziona; la mia Function deve essere la più astratta possibile per cui non so a priori su che tipo di dati devo effettuare il confronto (Stringhe, Numeri, Date). (In effetti avrei dovuto scrivere Valore1 as Variant , Valore2 as Variant, Operatore as String)
Ma comunque adattando il primo esempio penso che userò la soluzione con il Select Case!
Grazie ancora.
di scossa data: 27/03/2014 21:49:48
Non mi è chiara la tua necessità reale.
a) I valori sono solo integer?
b) ti serve una function da usare nel VBA o anche in una cella?
c) I valori sono nelle celle o sono variabili VBA?
di vmontal data: 27/03/2014 22:15:20
Rispondo prima con ordine:
1) i valori possono essere di qualunque tipi (Integer, String, date)
2) la Function mi serve in VBA;
3) i valori sono nelle celle;
Di seguito il codice che riproduce la funzione ContaSe; ed aggiungo per anticipare la domanda che ho dovuto ricorrere ad una Function personale piuttosto che della WorkSheetFunction.countif() perché (che ci crediate o no) in Excel 2003 utilizzare le WorkSheetFunction è un terno al lotto!
Function ContaSe(Elenco As Range, Operatore As String, Valore As Variant) As Integer
Dim I As Integer
ContaSe = 0
For I = 1 To Elenco.Count
Select Case Operatore
Case ">"
If Elenco(I) > Valore Then
ContaSe = ContaSe + 1
End If
Case "<"
If Elenco(I) < Valore Then
ContaSe = ContaSe + 1
End If
Case "="
If Elenco(I) = Valore Then
ContaSe = ContaSe + 1
End If
Case ">="
If Elenco(I) >= Valore Then
ContaSe = ContaSe + 1
End If
Case "<="
If Elenco(I) <= Valore Then
ContaSe = ContaSe + 1
End If
Case Else
MsgBox "Operatore errato! Valori ammessi <,<=,=,>=,>"
End Select
Next
End Function
|
di Zer0Kelvin data: 27/03/2014 22:36:35
Ciao.
Secondo me, puoi semplicemente usare Evaluate; e non mi sembra che non funzioni con le date, dal momento che esse non sono altro che valori numerici (devono essere vere date, non stringhe) ed utilizzare una function che restituisca un valore logico in base a valori e operatore fornito
Function confronta(V1 As Variant, V2 As Variant, Op As String) As Boolean
confronta = Evaluate(V1 & Op & V2)
End Function
Sub ccc()
Dim d1 As Date, d2 As Date
d1 = Date
d2 = Date - 1
MsgBox confronta(d1, d2, ">=")
End Sub |
di Zer0Kelvin data: 27/03/2014 22:46:41
A prima vista, questa funziona
Function confronta(V1 As Variant, V2 As Variant, Op As String) As Boolean
confronta = Evaluate(V1 & Op & V2)
End Function
Function ContaSe(Elenco As Range, Operatore As String, Valore As Variant) As Long
Dim C As Range
ContaSe = 0
For Each C In Elenco.Cells
If confronta(C.Value, Valore, Operatore) Then ContaSe = ContaSe + 1
Next C
End Function
|
di scossa data: 27/03/2014 22:53:38
cit. vmontal: "Function ContaSe(Elenco As Range, Operatore As String, Valore As Variant) As Integer"
scusami, ma cosa c'azzecca questo codice con la tua richiesta originale, così come illustrata nell'esempio del tuo primo post
Comunque l'udf sotto funziona perfettamente in Excel 2003:
In A1:A10 dati vari
=miocontase(A1:A5;"<";10)
In E1:E15 date varie
=miocontase(E1:E14;"<";DATA.VALORE("15/06/2000"))
In H1:H4 dati vari
=miocontase(H1:H4;"<=";"gamma")
Public Function MioContaSe(rng As Range, sOper As String, vVal As Variant) As Long
MioContaSe = Application.CountIf(rng, sOper & vVal)
End Function
Sub prova()
MsgBox MioContaSe(Range("A1:A15"), "<", 10)
End Sub
|
di vmontal data: 27/03/2014 23:46:33
@ Scossa
cit: vmontal "scrivere una Function a cui devo passare oltre a dei valori anche l'Operatore di confronto "
ci azzecca perché la mia richiesta era appunto come passare ad un Function un "Operatore di Confronto"
... e poi non ho detto che le WorkSheetFunction non funzionano, ma semplicemente che sono inaffidabili; ho sperimentato più volte comportamenti anomali (non funzionano) su uno stesso codice su medesime condizioni! (liberi di non credere)!
di Zer0Kelvin data: 28/03/2014 06:48:18
Resterebbe da capire "perchè" le WorkSheetFunction non ti funzionano; se le altre condizioni sono le stesse il problema è probabilmente dovuto ai dati passati alla funzione(per esempio, cerchi di contare delle date confrontandole con delle stringhe, o dei numeri che non hanno lo stesso numero di cifre decimali). L'unico problema con le WorkSheetFunction di cui sono a conoscenza, è che possono non avere lo stesso nome nelle varie versioni di Excel.
di vmontal data: 28/03/2014 07:58:13
cit. Zer0Kelvin: "Resterebbe da capire "perchè" le WorkSheetFunction non ti funzionano".
sono d'accordo! Ma questo sarà l'oggetto di un prossimo post.
di scossa data: 28/03/2014 10:39:25
cit.: "ci azzecca perché la mia richiesta era appunto come passare ad un Function un "Operatore di Confronto" "
Suvvia che hai capito bene cosa intendevo, perché se la tua richiesta fosse stata questa ti saresti già dato la risposta:
Calcola(Valore1 as Integer, Valore2 as Integer, Operatore as String) as Integer
Ma tu in realtà chiedevi non come *passare*, ma come *utilizzare* l'operatore passato.
E l'esempio che avevi fatto, due singoli integer e un operatore per "assemblare" una funzione, poco c'azzeccava con la reale necessita: emulare una funzione nativa di Excel, e quindi l'esempio era fuorviante. Tutto qui, niente di grave
cit.: "Ho sperimentato più volte comportamenti anomali (non funzionano) su uno stesso codice su medesime condizioni!"
Secondo me (opinione personale) quelli che chiami comportamenti anomali sono semplicemente dovuti al fatto che usare una WorksheetFunction in VBA richiede una appropriata gestione degli eventuali errori restituiti dalla funzione chiamata; gestione che è diversa se si usa la forma estesa (ad esempio Application.WorksheetFunction.CountIf), oppure la forma contratta (Application.CountIf).
Vuoi Approfondire?