A
1 32
2 25
3 45
4 78
5 48
Vorrei creare una funzione per cui io scrivo =ultimo(A1:A5) e mi
ritorna 48 nell'esempio.
Grazie mille
Adattando, al tuo caso, la formula suggerita da Ivano al link
http://tinyurl.com/3yzmcr, si avra':
=INDICE(A1:A5;CONFRONTA(2^1023;A1:A5))
> Grazie mille
Ciao
Pippo
La suddetta formula (valida anche in presenza di celle vuote), si applica,
quando nell'intervallo da esaminare, ci sono *solo* dati di tipo *numerico*
;
per le altre casistiche, dai uno sguardo al link http://tinyurl.com/38bpx4.
Ciao
Pippo
"Morrison" ha scritto:
Function ValAngoloBasso(rng As Range) As Variant
ValAngoloBasso = Cells(rng.Rows.Count, rng.Columns.Count)
End Function
inserita in un modulo puoi richiamarla dalle funzioni definite dall'utente
se ti serve sempre mettila in personal
ciao
r
Ciao r. Ciao Morrison.
Che corrisponde a:
=INDICE(A1:A5;RIGHE(A1:A5);COLONNE(A1:A5))
--
Maurizio Borrelli [Microsoft Excel MVP]
http://www.riolab.org
Con le funzioni di excel standard piu' o meno sono confident.
Volevo creare una funzione, ad esempio chiamata ultimo, che prende in
pasto un range.
Grazie mille
> >=INDICE(A1:A5;RIGHE(A1:A5);COLONNE(A1:A5))
> Ringrazio tutti per le risposte.
> Pero' il mio obiettivo era creare una classica funzione VBA, anche per
> impratichirmi con questo linguaggio.
> Con le funzioni di excel standard piu' o meno sono confident.
> Volevo creare una funzione, ad esempio chiamata ultimo, che prende in
> pasto un range.
Ciao Morrison.
Quindi?... Obiettivo raggiunto, no? Altro che "pero'"!
Facci capire: la funzione postata da "r" l'hai vista?
In seguito alla tuo giusto richiamo sono andato su google e l'ho visto
da li.
Tuttavia, non riesco a capire perche' non mi funziona.
L'ho messo in un modulo, la funzione viene riconosciuta, ma come
valore mi restituisce sempre zero.
Ciao
Qualcuno mi conferma che quella funzione e' OK nella precedente
versione di Excel?
Thanks
La funzione suggerita da "R" restituisce l'ultima cella del tuo intervallo
che, probabilmente, e' *vuota*.
Prova la seguente funzione, valida anche in presenza di celle *vuote* e
disposte in una qualunque posizione del tuo intervallo:
'================================================
Public Function ValUltima(rng As Range) As Variant
Dim u As Variant
Dim Nr As Integer
Dim Nc As Integer
With rng
Nr = .Row + .Rows.Count - 1
Nc = .Column
End With
With Cells(Nr, Nc)
If .Value = "" Then
If Not Intersect(rng, .End(xlUp)) Is Nothing Then
u = .End(xlUp).Value
End If
Else
u = .Value
End If
End With
ValUltima = u
End Function
'===============================================
PS: Fammi sapere ! ;-)))
Ciao
Pippo
[cut]
Un'altra possibilita' interessante , e' quella di richiamare, le funzioni
(se sono previste anche in Vba) del foglio di lavoro excel, da Vba.
Riprendendo ad es., la formula di Ivano, valida *solo* per un intervallo
*numerico*:
=INDICE(A1:A5;CONFRONTA(2^1023;A1:A5))
e' possibile utilizzarla anche con Vba, dove pero', le corrispondenti
"funzioni excel" avranno una notazione "inglese".
Prova:
'======================================
Public Function Ultima(rng As Range) As Variant
'Valida per un intervallo numerico
With Application.WorksheetFunction
Ultima = .Index(rng, (.Match(2 ^ 1023, rng)))
End With
End Function
'=====================================
Ciao
Pippo
> avevo dimenticato una cosa ... chiedo scusa
> ecco quella corretta
> Function ValAngoloBasso(rng As Range) As Variant
> ValAngoloBasso = Cells(rng.Row + rng.Rows.Count - 1, rng.Column +
> rng.Columns.Count - 1)
> End Function
ciao r.
Molto rischioso questo modo di scrivere. Qui "Cells" si riferisce al
Foglio di lavoro attivo e non e' in relazione con l'argomento "rng".
Dopo aver aggiunto l'indispensabile metodo:
Sub Volatile([Volatile])
Membro di Excel.Application
cosi':
Function ValAngoloBasso(rng As Range) As Variant
Application.Volatile True
ValAngoloBasso = Cells(rng.Row + rng.Rows.Count - 1 _
, rng.Column + rng.Columns.Count - 1)
End Function
prova a usarla in un Foglio di lavoro (Foglio1). Poi, in un altro
(Foglio2), a riferirti alla cella alla quale hai assegnato la formula
con tale funzione. Il ricalcolo di ValAngoloBasso fara' riferire "Cells"
a Foglio1 o a Foglio2 a seconda di quale e' attivo in quel momento.
Poi prova cosi':
Function ValAngoloBasso2(rng As Range) As Variant
Application.Volatile True
With rng
ValAngoloBasso2 = .Cells(.Rows.Count, .Columns.Count)
End With
End Function
che e' appunto quello che, distrattamente, mi pareva di aver letto nel
tuo primo post del 3D.
Scusa Maurizio, sulla base delle tue osservazioni, la funzione che avevo
suggerito in questo thread, e' stata da me modifica nel seguente modo:
'================================================
Public Function ValUltima(rng As Range) As Variant
Dim u As Variant
Dim Nr As Integer
Dim Nc As Integer
With rng
Nr = .Rows.Count
Nc = .Column
End With
With rng.Cells(Nr, Nc)
If .Value = "" Then
If Not Intersect(rng, .End(xlUp)) Is Nothing Then
u = .End(xlUp).Value
End If
Else
u = .Value
End If
End With
ValUltima = u
End Function
'==============================================
Giusto?
Inoltre, *non* ho notato differenze di funzionamento, nella suddetta
funzione, in assenza o presenza dell'istruzione (ho provato anche a leggere
quanto riportato nella guida Vba...):
"Application.Volatile True".
Puoi darmi qualche ulteriore chiarimento?
Ciao e grazie milleeeee
Pippo
[...]
> > Dopo aver aggiunto l'indispensabile metodo:
> > Sub Volatile([Volatile])
> > Membro di Excel.Application
[...]
> Scusa Maurizio, sulla base delle tue osservazioni, la funzione che avevo
> suggerito in questo thread, e' stata da me modifica nel seguente modo:
> '================================================
> Public Function ValUltima(rng As Range) As Variant
[...]
> End Function
> '==============================================
> Giusto?
> Inoltre, *non* ho notato differenze di funzionamento, nella suddetta
> funzione, in assenza o presenza dell'istruzione (ho provato anche a
> leggere quanto riportato nella guida Vba...):
> "Application.Volatile True".
> Puoi darmi qualche ulteriore chiarimento?
Ciao Pippo
Application.Volatile
Come prima cosa vediamo un esempio concreto dell'effetto di questa
istruzione, per cui scriviamo la seguente funzione Visual Basic in un
Modulo standard, a visibilita' pubblica, del progetto VBA di una nuova
Cartella di lavoro di Excel:
Public Function VbCasuale()
VbCasuale = Rnd
End Function
Essa restituisce il valore casuale ottenuto mediante la:
Function Rnd([Number]) As Single
Member of VBA.Math
ed e' quindi analoga alla Funzione:
CASUALE()
di Excel.
Accertiamoci che il Ricalcolo sia impostato su Automatico quindi
sperimentiamo il comportamento delle due Funzioni usandole in due
Formule che immettiamo nelle Celle di un Foglio di lavoro della suddetta
Cartella di lavoro:
[Cartel1]
Foglio1
A1: =CASUALE()
A2: =VbCasuale()
Ora immettiamo un valore qualsiasi in una delle restanti Celle, per
esempio:
A3: 123
e osserviamo che il valore di "A1" e' cambiato, a differenza di quello
di "A2".
Modifichiamo "VbCasuale" cosi':
Public Function VBCasuale()
Application.Volatile True
VBCasuale = Rnd
End Function
e immettiamo un nuovo valore in:
A3: 456
Osserveremo che ora si modifica il valore di entrambe le celle "A1" e
"A2", e cosi' per ogni nuova immissione, come pure a ogni nuovo
ricalcolo (F9).
Detto questo... Potrebbe anche essere che nel caso specifico dell'uso
della tua funzione "ValUltima" sia abbastanza improbabile, o persino
impossibile, ottenere una situazione in cui "Volatile" faccia la
differenza, tuttavia fra la certezza di ottenere il ricalcolo di
"ValUltima" in qualsiasi circostanza e il dubbio, personalmente
preferisco la certezza. Ovvero, quando scrivo una UDF ho bisogno di
essere *certo* che venga *sempre* ricalcolata e non ho intenzione di
occupare parte del mio tempo in test per verificare se posso risparmiare
quell'istruzione. Sara' un approccio pragmatico-scaramantico, piuttosto
che scientifico, ma... funziona. ;-)
[...]
> sulla base delle tue osservazioni, la funzione che avevo
> suggerito in questo thread, e' stata da me modifica nel seguente modo:
> '================================================
> Public Function ValUltima(rng As Range) As Variant
> Dim u As Variant
> Dim Nr As Integer
> Dim Nc As Integer
> With rng
> Nr = .Rows.Count
> Nc = .Column
> End With
> With rng.Cells(Nr, Nc)
> If .Value = "" Then
> If Not Intersect(rng, .End(xlUp)) Is Nothing Then
> u = .End(xlUp).Value
> End If
> Else
> u = .Value
> End If
> End With
> ValUltima = u
> End Function
> '==============================================
> Giusto?
Ciao Pippo.
Giusto?... Si', riguardo la questione dei riferimenti. Se poi e' giusta,
del tutto, questa funzione... dipende. Dipende dallo scopo per cui e'
stata scritta. Vediamo...
1.
Dim Nr As Integer
Dim Nc As Integer
Sostiene la Guida che le variabili di tipo "Integer":
"sono memorizzate come numeri a 16 bit (2 byte) compresi nell'intervallo
fra -32.768 e 32.767."
quindi queste tue dichiarazioni garantirebbero una esecuzione senza
errori fino a Excel 97 *escluso*, perche' da quella versione il numero
delle righe di un Foglio di lavoro e' passato da 16.384 a 65.536.
Tuttavia le versioni precedenti Excel 97 incorporavano un differente
ambiente di sviluppo...
Volendo mantenere queste dichiarazioni come minimo dovresti,
all'ingresso nella funzione, scrivere del codice che preveda l'uscita
dalla funzione se l'indirizzo dell'argomento di tipo Excel.Range si
riferisce a righe il cui numero e' superiore a 16.384, oppure aggiungere
una routine di gestione dell'errore di run-time che otterresti in tal
caso.
Meglio quindi dichiarare:
Dim Nr As Long
Dim Nc As Long
come ormai ripetuto un po' da tutti e le centinaia di volte in questo
ng, negli ultimi 5 anni. O sono di piu'? Pippo, pensavo li leggessi
tutti anche tu i post di questo ng! ;-)
2.
With rng
Nr = .Rows.Count
Nc = .Column
End With
Con questo blocco ottieni, in "Nr", il numero delle righe di cui e'
composto l'intervallo "rng" e, in "Nc", il numero di colonna della prima
cella di "rng".
Cioe', nel caso dell'intervallo "W100:Z110":
Nr = 11
Nc = 23
Secondo me gia' chiamare con nomi simili due variabili destinate a
contenere valori che rappresentano cose diverse e' fuorviante: il
conteggio del numero di righe (o di colonne) di cui e' composto un
intervallo, e il numero della riga (o colonna) cui appartiene un
intervallo sono due concetti molto diversi.
Di conseguenza, quando scrivi:
With rng.Cells(Nr, Nc)
che intenzioni hai? Nel caso dell'intervallo dell'esempio di prima,
"W100:Z110", otterresti di riferirti alla Cella di indirizzo:
AS110
come puoi verificare tu stesso digitando, nella mai troppo spesso
evocata finestra Immediata, e concludendo con Invio:
?range("W100:Z110").cells(range("W100:Z110").Rows.Count,range("W100:Z110").Column).address
Eccetera.
Ancora grazie.
[cut]
> Detto questo... Potrebbe anche essere che nel caso specifico dell'uso
> della tua funzione "ValUltima" sia abbastanza improbabile, o persino
> impossibile, ottenere una situazione in cui "Volatile" faccia la
> differenza, tuttavia fra la certezza di ottenere il ricalcolo di
> "ValUltima" in qualsiasi circostanza e il dubbio, personalmente preferisco
> la certezza. Ovvero, quando scrivo una UDF ho bisogno di essere *certo*
> che venga *sempre* ricalcolata e non ho intenzione di occupare parte del
> mio tempo in test per verificare se posso risparmiare quell'istruzione.
> Sara' un approccio pragmatico-scaramantico, piuttosto che scientifico,
> ma... funziona. ;-)
OK,.. grazie mille Maurizio,..sei sempre preciso ed esaustivo nelle
risposte! ;-)
Ciao
Pippo
Si', hai perfettamente ragione (come sempre), e' stato un errore di
distrazione! :-(
>
> 2.
>
> With rng
> Nr = .Rows.Count
> Nc = .Column
> End With
>
> Con questo blocco ottieni, in "Nr", il numero delle righe di cui e'
> composto l'intervallo "rng" e, in "Nc", il numero di colonna della prima
> cella di "rng".
>
> Cioe', nel caso dell'intervallo "W100:Z110":
>
> Nr = 11
> Nc = 23
>
> Secondo me gia' chiamare con nomi simili due variabili destinate a
> contenere valori che rappresentano cose diverse e' fuorviante: il
> conteggio del numero di righe (o di colonne) di cui e' composto un
> intervallo, e il numero della riga (o colonna) cui appartiene un
> intervallo sono due concetti molto diversi.
>
> Di conseguenza, quando scrivi:
>
> With rng.Cells(Nr, Nc)
>
> che intenzioni hai? Nel caso dell'intervallo dell'esempio di prima,
> "W100:Z110", otterresti di riferirti alla Cella di indirizzo:
>
> AS110
>
> come puoi verificare tu stesso digitando, nella mai troppo spesso evocata
> finestra Immediata, e concludendo con Invio:
>
> ?range("W100:Z110").cells(range("W100:Z110").Rows.Count,range("W100:Z110").Column).address
*Accidentiiiiiiiiiiii!* :-(((
Avevo scritto la suddetta funzione, considerando un intervallo di input
costituito da *una* sola *colonna* e da un numero variabile di righe, del
tipo cioe':
"A1:A100".
Con il suddetto intervallo, ottenevo:
Nr=100
Nc=1
puntando all'ultima cella "A100" dell'intervallo "A1:A100".
Quindi, la funzione, per il mio scopo, *sembrava* restituire il giusto
risultato; pero', cambiando intervallo, ad es. "B1:B100", mi sono reso conto
di non ottenere il riferimento all'ultima cella "B100".
Potresti darmi una "dritta" per modificare e ottimizzare la suddetta
funzione? ;-))
PS: grazie a te, mi sono anche reso conto di aver creato *confusione* a chi
ha inviato ("Morrison") il post di apertura, chiedendo un aiuto, ed
invece.....credo che per un po' *non* inviero' piu' post di "risposta":
inviero' solo post per chiedere direttamente un vostro aiuto! :-((
Ciao e grazie milleeeeee
Pippo
"Maurizio Borrelli" ha scritto:
vero ... era più corretta quella buttata d'istinto ... :-)
grazie
ciao
r
p.s.
ho l'impressione che i miei post non vengano letti, e non risultano
cronologicamente ordinati con quelli scritti dopo ... sapete spiegarmi come
mai?
[...]
> > Function ValAngoloBasso2(rng As Range) As Variant
> > Application.Volatile True
> > With rng
> > ValAngoloBasso2 = .Cells(.Rows.Count, .Columns.Count)
> > End With
> > End Function
> > che e' appunto quello che, distrattamente, mi pareva di aver letto nel
> > tuo primo post del 3D.
> vero ... era più corretta quella buttata d'istinto ... :-)
'nzomma... Anche in quella c'era un "Cells" che faceva riferimento al
Foglio di lavoro attivo.
[...]
> p.s.
> ho l'impressione che i miei post non vengano letti,
Anche io. E non solo i tuoi. Infatti Pippo in altro post di questo 3D mi
chiede:
"Potresti darmi una 'dritta' per modificare e ottimizzare la suddetta
funzione?"
eppure la risposta e' quella "ValAngoloBasso2" qui sopra che dovrebbe
aver visto ormai da qualche ora. Vediamo se questo mio post lo legge.
> e non risultano cronologicamente ordinati con quelli scritti dopo ... sapete
> spiegarmi come mai?
Tu con cosa leggi i ng? Vediamo...
X-Newsreader: Microsoft CDO for Windows 2000
No, non so che dirti. Mi spiace. Aspettiamo qualcuno che in queste cose
ci sguazzi.
[cut]
>Pippo in altro post di questo 3D mi chiede:
>
> "Potresti darmi una 'dritta' per modificare e ottimizzare la suddetta
> funzione?"
>
> eppure la risposta e' quella "ValAngoloBasso2" qui sopra che dovrebbe aver
> visto ormai da qualche ora. Vediamo se questo mio post lo legge.
Si', Maurizio, ti ringrazio, ho letto la funzione "ValAngoloBasso2" , pero',
la funzione che avevo suggerito, *cercava* di compredenre anche il caso in
cui l'intervallo di input (che ho supposto costituito da una *sola* colonna
ed un numero variabile di righe) avesse alcune celle *vuote* (quindi anche
l'ultima) e, in tal caso, venisse restituita l'ultima cella con valore
*non* vuoto.
Quanto sopra, *non* e' certamente in linea con l'oggetto del post; ho
cercato pero', di estendere il problema, ma, ottenedo, scarsi risultati....
:-(((
PS:
Quando ti e' possibile, puoi rispondere a quel post in questo stesso thread.
Ciao e grazie mille per l'infinita disponibilita' e competenza!
Pippo
Ciao Pippo.
[...]
> la funzione che avevo suggerito, *cercava* di compredenre anche
> il caso in cui l'intervallo di input (che ho supposto costituito da
> una *sola* colonna ed un numero variabile di righe) avesse alcune celle
> *vuote* (quindi anche l'ultima) e, in tal caso, venisse restituita
> l'ultima cella con valore *non* vuoto.
> Quanto sopra, *non* e' certamente in linea con l'oggetto del post; ho
> cercato pero', di estendere il problema, ma, ottenedo, scarsi
> risultati....
[..]
> Quando ti e' possibile, puoi rispondere a quel post in questo stesso
> thread.
Ciao Pippo.
Invece rispondo qui perche' non mi piace saltapicchiare alla ricerca dei
post. :P
Insomma, Pippo... da una funzione che restituisce il valore assegnato
alla cella in basso a destra ***di un intervallo dato*** vuoi passare a
un'altra funzione che a partire da ***una cella data*** restituisce il
valore assegnato all'ultima cella piena nella colonna a partire dalla
cella data.
E' questo il problema? Perche', come ben sai, *prima* si enuncia il
problema, *poi* si cerca la soluzione.
Pertanto, cosa vuoi che venga restituito da questa tua funzione nel caso
in cui la cella di input, e tutte le sottostanti, siano vuote? Fin che
non si definiscono cose come queste e' inutile mettersi a scrivere il
codice.
Mettiamo che a questa domanda tu risponda: Zero. Oppure Stringa-nulla
(""). Non trovi che in quel caso la tua funzione fornirebbe una
informazione ingannevole? Ci "direbbe" che esiste una ultima cella piena
e che il suo valore e' Zero, o Stringa-nulla. Che ce ne facciamo di
questa informazione? Prospettami un caso concreto in cui e' utile, con
una funzione apposita, ottenere il valore dell'ultima cella piena in una
colonna a partire da una cella data della stessa colonna, oppure Zero (o
Stringa-nulla) sia nel caso in cui esista tale cella o che non esista.
OK! ;-)
> Insomma, Pippo... da una funzione che restituisce il valore assegnato alla
> cella in basso a destra ***di un intervallo dato*** vuoi passare a
> un'altra funzione che a partire da ***una cella data*** restituisce il
> valore assegnato all'ultima cella piena nella colonna a partire dalla
> cella data.
>
> E' questo il problema? Perche', come ben sai, *prima* si enuncia il
> problema, *poi* si cerca la soluzione.
[cut]
Il problema potrebbe essere cosi' enunciato:
A partire da un intervallo "A1:A100" di input (costituito da una colonna e
da un certo numero di righe) e *non* da una data cella , voglio trovare
qual'e' il valore dell'ultima cella con valore *non* *vuoto*.
Il suddetto intervallo, puo' avere alcune celle *vuote*: nel caso fosse
costituito da *tutte* celle *vuote*, debbo ottenere, dalla funzione, una
"stringa nulla".
Un utilizzo, forse banale, potrebbe essere quello di voler tenere sotto
controllo l'ultimo dato inserito (quindi l'ultima cella *non* *vuota*)
nell'intervallo "A1:A100".
Ciao e grazie milleeeeeeee
Pippo
[...]
> PS: grazie a te, mi sono anche reso conto di aver creato *confusione* a
> chi ha inviato ("Morrison") il post di apertura, chiedendo un aiuto, ed
> invece.....credo che per un po' *non* inviero' piu' post di "risposta":
> inviero' solo post per chiedere direttamente un vostro aiuto! :-((
Ciao Pippo.
... e questo mi dispiacerebbe molto! Perche' non c'e' niente di meglio
che confrontare le proprie soluzioni con quelle degli altri, permettendo
a chi ci legge di valutare e scegliere in base alle proprie necessita'
che spesso sono solo parzialmente espresse. Inoltre, credimi, si impara
anche da soluzioni o ipotesi un po'... arrischiate o approssimative.
Perche' si ha comunque la possibilita' di vedere un altro lato del
problema, un altro approccio.
Di' la verita'... Quando mai saremmo riusciti a affrontare i discorsi
fatti in questo 3D se tu non fossi intervenuto? A me e' stato
sicuramente utile ragionare con te. Spero lo sia stato anche per te e
per chi ha avuto la bonta' di seguirci.
Se invece io, involontariamente, mi sono espresso in modo troppo brusco
o offensivo, ti prego di tutto cuore di perdonarmi.
> Di' la verita'... Quando mai saremmo riusciti a affrontare i discorsi
> fatti in questo 3D se tu non fossi intervenuto? A me e' stato sicuramente
> utile ragionare con te. Spero lo sia stato anche per te e per chi ha avuto
> la bonta' di seguirci.
Apprezzo la tua UMILTA' (oltre che la tua bravura),.....ero un po'
incavolato, arrabbiato, inca**ato con me stesso, ma, in realta', piu' per
problemi *miei* personali.... :-((
> Se invece io, involontariamente, mi sono espresso in modo troppo brusco o
> offensivo, ti prego di tutto cuore di perdonarmi.
NO, nessun tuo discorso brusco o offensivo, almeno non in questo caso....
;-)))))
Ciao Pippo.
[...]
> Il problema potrebbe essere cosi' enunciato:
> A partire da un intervallo "A1:A100" di input (costituito da una colonna
> e da un certo numero di righe)
> e *non* da una data cella , voglio trovare
> qual'e' il valore dell'ultima cella con valore *non* *vuoto*.
A partire da A100 e andando in su fino a A1 e fermandoci alla prima
cella piena che incontriamo, giusto?
> Il suddetto intervallo, puo' avere alcune celle *vuote*: nel caso fosse
> costituito da *tutte* celle *vuote*, debbo ottenere, dalla funzione, una
> "stringa nulla".
> Un utilizzo, forse banale, potrebbe essere quello di voler tenere sotto
> controllo l'ultimo dato inserito (quindi l'ultima cella *non* *vuota*)
> nell'intervallo "A1:A100".
Ammettiamo abbia senso. Dico ammettiamo perche' la questione dei "buchi"
non mi convince.
Io pero' la "sperimentazione" non la farei a partire dall'intervallo
ingannevole, speciale, particolare, "A1:A...", ma, per esempio, da
"C5:C10". Perche' sta in una videata, cioe' lo si tiene d'occhio
agevolmente mentre si sperimenta e 10, 100 o 1.000 non fa differenza dal
punto di vista di quel che dobbiamo fare e, soprattutto, non comprende
la prima cella del foglio, "A1". Insomma... mai studiare soluzioni
partendo da "A1".
La "sperimentazione", "ricerca", "studio", chiamalo come vuoi, la farei
nella finestra Immediata. Cominciando con un Foglio vuoto.
Per prima cosa individuiamo l'ultima cella dell'intervallo:
?range("C5:C10").item(range("C5:C10").Rows.Count).address
$C$10
Bene. L'indirizzo corrisponde.
Ora a partire da questa cella individuiamo la prima cella piena
spostandoci verso l'alto:
?range("C10").End(xlUp).Address
$C$1
Giustamente. Perche' il foglio e' vuoto. Pero' noi in questo caso
avremmo voluto ottenere "C5". Come fare? Potremmo usare una struttura
del tipo:
Se riga < RigaDellaPrimaCellaDell'Intervallo allora
riga = RigaDellaPrimaCellaDell'Intervallo
Fine Se
Ora abbiamo tutte le informazioni che ci servono per scrivere un
abbozzo:
Public Sub Test()
Dim rngIn As Excel.Range
Set rngIn = Range("C5:C10")
Debug.Print "rngIn: "; rngIn.Address
With rngIn
Dim rngLast As Excel.Range
Set rngLast = .Item(.Rows.Count)
With rngLast
Debug.Print "rngLast: "; .Address
Dim rngOut As Excel.Range
Set rngOut = .End(xlUp)
Debug.Print "rngOut: "; rngOut.Address
End With
If rngOut.Row < .Row Then
Set rngOut = .Item(1)
End If
End With
Debug.Print "rngOut: "; rngOut.Address
Set rngOut = Nothing
Set rngLast = Nothing
Set rngIn = Nothing
End Sub
Che, ricordiamo: sempre a foglio vuoto, eseguito produce l'output
seguente:
rngIn: $C$5:$C$10
rngLast: $C$10
rngOut: $C$1
rngOut: $C$5
Ora immettiamo un valore nell'intervallo:
C5: 123
Eseguiamo e otteniamo:
rngIn: $C$5:$C$10
rngLast: $C$10
rngOut: $C$5
rngOut: $C$5
Bene. Cancelliamo il valore in "C5" e immettiamo:
C9: 123
Otteniamo:
rngIn: $C$5:$C$10
rngLast: $C$10
rngOut: $C$9
rngOut: $C$9
Possiamo passare alla scrittura della funzione, a partire dall'abbozzo
qui sopra.
Public Function UltimoValoreImmesso(ByVal rng _
As Excel.Range) As Variant
Dim rngIn As Excel.Range
Dim rngLast As Excel.Range
Dim rngOut As Excel.Range
Set rngIn = rng
With rngIn
Set rngLast = .Item(.Rows.Count)
Set rngOut = rngLast.End(xlUp)
If rngOut.Row < .Row Then
Set rngOut = .Item(1)
End If
End With
Debug.Print "rngOut: "; rngOut.Address
UltimoValoreImmesso = rngOut.Value
Set rngOut = Nothing
Set rngLast = Nothing
Set rngIn = Nothing
End Function
Che testeremo usando la routine:
Public Sub UltimoValoreImmesso_test()
Debug.Print "'"; UltimoValoreImmesso(Range("C5:C10")); "'"
End Sub
Ciao Pippo.
[...]
> Apprezzo la tua UMILTA' (oltre che la tua bravura),
:DDDD
Scusa se mi smascello dal ridere. Mi capita sempre quando leggo a
proposito della mia umilta'. Riguardo la bravura come potrei non
concordare con te?
:DDDD
> .....ero un po'
> incavolato, arrabbiato, inca**ato con me stesso, ma, in realta', piu'
> per problemi *miei* personali.... :-((
Mi spiace molto. Ti faccio tanti auguri.
> > Se invece io, involontariamente, mi sono espresso in modo troppo
> > brusco o offensivo, ti prego di tutto cuore di perdonarmi.
> NO, nessun tuo discorso brusco o offensivo, almeno non in questo
> caso....
> ;-)))))
Ahi!... Devo stare piu' attento, vero? Ciao!
> A partire da A100 e andando in su fino a A1 e fermandoci alla prima
> cella piena che incontriamo, giusto?
Giusto! ;-)
>> Il suddetto intervallo, puo' avere alcune celle *vuote*: nel caso fosse
>> costituito da *tutte* celle *vuote*, debbo ottenere, dalla funzione, una
>> "stringa nulla".
>> Un utilizzo, forse banale, potrebbe essere quello di voler tenere sotto
>> controllo l'ultimo dato inserito (quindi l'ultima cella *non* *vuota*)
>> nell'intervallo "A1:A100".
>
> Ammettiamo abbia senso. Dico ammettiamo perche' la questione dei "buchi"
> non mi convince.
Si', hai ragione...diciamo che e' un modo per esercitarsi ed imparare
il Vba.
NON ho PAROLE: ho imparato tantissimo da questa tua meticolosa
spiegazione.
Un'ultima curiosita':seguendo il tuo esempio, ho notato che, nella
"finestra immediata", il numero " 123 ", viene scritto cono uno
"spazio" prima della prima cifra ( 1) ed uno dopo l'ultima cifra
(3 ) :
c'e' un motivo particolare?
PS.
Ho letto il tuo curricolo,.. il tuo stile nello scrivere codice, mi fa
sospettare una tua approfondita conoscenza e provenienza da altri
linguaggi di programmazione, piu' *sofisticati* (non so se e' il
termine giusto..) del Vba..
..cmq molti di Voi, siete per me, volendo fare un paragone sportivo e
di parte ;-), come i "Maradona" del pallone: impossibile raggiungere i
vostri livelli.
Ciao e grazie mille per la disponibilita' e competenza!
Pippo
Se alla funzione diamo in pasto, ad esempio, il range ("G82:G89")
restituisce correttamente il valore 8
Ma se gli diamo in pasto ("G80:G87"), restituisce 1
Sto guardando il codice, ma non sono ancora riuscito a capire perche'
Ciao
> Ciao, in effetti il "problema" posto da Pippo, relativamente
> all'ultima cella vuota, esiste.
> Mi stavo studiando la nuova funzione proposta di Maurizio.
> Dalle mie prove mi vengono fuori dei valori non corretti, ma solo in
> determinata circostanze. Mi spiego.
> Supponente di avere una sequenza di numeri, nel range ("G80:G87")
> 1
> 2
> 3
> 4
> 5
> 6
> 7
> 8
>
> Se alla funzione diamo in pasto, ad esempio, il range ("G82:G89")
> restituisce correttamente il valore 8
> Ma se gli diamo in pasto ("G80:G87"), restituisce 1
>
> Sto guardando il codice, ma non sono ancora riuscito a capire perche'
Il codice scritto da Maurizio, funziona per quello che chiedevo: esaminare
l'intervallo a partire dall'ultima cella, quindi, *escludendola*, anche se
*non* fosse vuota.
Quando all'ultima cella dell'intervallo, applichiamo il metodo "End(xlUp)",
viene trovata la prima cella *non* vuota escludendo *sempre* l'ultima cella
dell'intervallo, indipendentemente se contiene valori o e' vuota.
Puoi fare delle prove, posizionandoti in una cella e premendo i
conteporaneamente i *due* tasti tasti "Ctrl + Shift" (che equivale ad
applicare il metodo "End(xlUp)" da Vb).
Per il funzionamento in base a quello che chiedi e, nell'attesa
dell'intervento di *Maurizio*, ho modificato il suo codice (credo
sicuramente da migliorare) nel modo seguente che, *sembra* funzionare:
'=========================================
Public Function UltimoValoreImmesso(ByVal rng _
As Excel.Range) As Variant
Dim rngIn As Excel.Range
Dim rngLast As Excel.Range
Dim rngOut As Excel.Range
UltimoValoreImmesso = ""
Set rngIn = rng
With rngIn
Set rngLast = .Item(.Rows.Count)
If (Len(rngLast.Value)) = 0 Then
Set rngOut = rngLast.End(xlUp)
If rngOut.Row < .Row Then
Set rngOut = .Item(1)
End If
Else
Set rngOut = rngLast.Item(1)
End If
End With
With rngOut
If Len(.Value) Then
Debug.Print "rngOut: "; rngOut.Address
UltimoValoreImmesso = .Value
End If
End With
Set rngOut = Nothing
Set rngLast = Nothing
Set rngIn = Nothing
End Function
'====================================
Ciao
Pippo
Ops! ;-)
'=============================================
Debug.Print "rngOut: "; rngOut.Address '<===== da modificare in .Address
'==============================================
Quindi:
'==============================================
Public Function UltimoValoreImmesso(ByVal rng _
As Excel.Range) As Variant
Dim rngIn As Excel.Range
Dim rngLast As Excel.Range
Dim rngOut As Excel.Range
UltimoValoreImmesso = ""
Set rngIn = rng
With rngIn
Set rngLast = .Item(.Rows.Count)
If (Len(rngLast.Value)) = 0 Then
Set rngOut = rngLast.End(xlUp)
If rngOut.Row < .Row Then
Set rngOut = .Item(1)
End If
Else
Set rngOut = rngLast.Item(1)
End If
End With
With rngOut
If Len(.Value) Then
Debug.Print "rngOut: "; .Address
UltimoValoreImmesso = .Value
End If
End With
Set rngOut = Nothing
Set rngLast = Nothing
Set rngIn = Nothing
End Function
'=============================
Ciao
Pippo
>>> Ciao, in effetti il "problema" posto da Pippo, relativamente
>>> all'ultima cella vuota, esiste.
>>> Mi stavo studiando la nuova funzione proposta di Maurizio.
>>> Dalle mie prove mi vengono fuori dei valori non corretti, ma solo in
>>> determinata circostanze. Mi spiego.
>>> Supponente di avere una sequenza di numeri, nel range ("G80:G87")
>>> 1
>>> 2
>>> 3
>>> 4
>>> 5
>>> 6
>>> 7
>>> 8
>>>
>>> Se alla funzione diamo in pasto, ad esempio, il range ("G82:G89")
>>> restituisce correttamente il valore 8
>>> Ma se gli diamo in pasto ("G80:G87"), restituisce 1
[cut]
Se il tuo intervallo, es. "A2:A5", si presenta con delle celle "vuote"
*solo* in coda:
A2=3344
A3=6666
A4=VUOTA
A5=VUOTA
..... allora puoi utilizzare la seguente formula senza usare le macro:
=SE(CONTA.VUOTE(A2:A5)<>RIGHE(A2:A10);SCARTO(A2;CONTA.VALORI(A2:A5)-1;0);"")
...che restituisce un valore "vuoto", *solo* quando, *tutte* le celle
dell'intervallo in esame, sono "vuote".
Ciao
Pippo
Ops.;-)
=SE(CONTA.VUOTE(A2:A5)<>RIGHE(A2:A5);SCARTO(A2;CONTA.VALORI(A2:A5)-1;0);"")
Ciao
Pippo
Grazie mille Pippo, sembra effettivamente funzionare.
Ciao Pippo.
> Il codice scritto da Maurizio, funziona per quello che chiedevo: esaminare
> l'intervallo a partire dall'ultima cella, quindi, *escludendola*, anche se
> *non* fosse vuota.
Ok!
> Quando all'ultima cella dell'intervallo, applichiamo il metodo "End(xlUp)",
> viene trovata la prima cella *non* vuota escludendo *sempre* l'ultima cella
> dell'intervallo, indipendentemente se contiene valori o e' vuota.
> Puoi fare delle prove, posizionandoti in una cella e premendo i
> conteporaneamente i *due* tasti tasti "Ctrl + Shift" (che equivale ad
> applicare il metodo "End(xlUp)" da Vb).
Piu' esattamente si tratta della combinazione di tasti:
Ctrl+Freccia<Su|Giu|Destra|Sinistra>
ovvero, dalla Guida:
CTRL+TASTO DI DIREZIONE
che sposta al bordo dell'area dati (area dati: Intervallo di celle
contenente dati e limitato da celle vuote o dai bordi del foglio dati.)
Piu' interessante ricordare che il metodo "End" corrisponde alla
generalmente ignorata "Modalita' Fine" del Foglio di lavoro. Prova a
premere il tasto "Fine" e osserva il messaggio nella Barra di stato.
Premilo ancora. Poi ancora. Visto? Quando sei in "Modalita' Fine" premi
una delle Frecce di direzione. End, Up. End, Down. End, Left. End,
Right. Il comportamento del Foglio di lavoro riprodotto dal metodo End,
appunto.
--
Maurizio Borrelli [Microsoft MVP - Excel]
http://www.riolab.org/
OK,.. in effetti conoscevo l'esatta combinazione dei tasti, ma l'ho scritta
in modo errato.
> ovvero, dalla Guida:
>
> CTRL+TASTO DI DIREZIONE
> che sposta al bordo dell'area dati (area dati: Intervallo di celle
> contenente dati e limitato da celle vuote o dai bordi del foglio dati.)
>
> Piu' interessante ricordare che il metodo "End" corrisponde alla
> generalmente ignorata "Modalita' Fine" del Foglio di lavoro. Prova a
> premere il tasto "Fine" e osserva il messaggio nella Barra di stato.
> Premilo ancora. Poi ancora. Visto? Quando sei in "Modalita' Fine" premi
> una delle Frecce di direzione. End, Up. End, Down. End, Left. End, Right.
> Il comportamento del Foglio di lavoro riprodotto dal metodo End, appunto.
Grazie,...ma del *tuo* codice che ho modificato, cosa ne pensi? ;-)))