› Excel e gli applicativi Microsoft Office › Funzione ricorsiva VBA per strutturazione file Excel
-
AutoreArticoli
-
Buongiorno a tutti. Ho il seguente problema, in diversi files Excel ho la necessità di formattare i dati. In particolare ho una colonna che mi identifica il livello di nidificazione degli stessi. In pratica qualcosa di simile:
1
2
3
3
3
2
3
3
4
4
2
3
Devo scorrere questa sequenza di numeri (ovviamente a priori non so quanto possa essere profondo il livello di nidificazione).Il risultato che devo ottenere è qualcosa di simile:
A1
B1
C1
C2
C3
B2
D1
D2
E1
E2
B3
F1
Qualche idea su come possa fare?Ciao
Spiega la logica con cui vuoi tradurre da numeri a lettere + numero
Non capisco la lettera D da dove arrivi.
Cerca di speigare con parole come costruire il tuo elenco nidificato.
Ciao
Luca
Grazie per l'attenzione Luca. In sostanza, diciamo che le lettere e i numeri sono dei progressivi. Il primo livello (1) è sempre identificato con la lettera A e seguito da un numero che identifica il progressivo degli oggetti di livello 1. Passando ai livelli a scendere, avrò sempre una lettera ed un numero, progressivi a parità di livello, ma univoci a livello di albero...Meglio che allego un immagine...
Spero adesso sia più chiaro....
Ciao Vediamo cosa si può fare.
Rituieni che
a) i numeri possano superare il 9?
b) le lettere possano superare la Z? (nel caso AA, AB, AC...BA, BB, BC...?)
c) i livelli arrivano fino a 4 O puoi averne di più?
Ciao
Luca
Buongiorno a te 🙂
a) I numeri che sono legati alla lettera non sono un gran problema. Nella situazione reale sono salvati in un'altra colonna e quindi alla mia lettera ci lego il numero che trovo nell'altra colonna. Ho messo i numeri negli esempi solo per chiarirmi le idee e rendere la cosa più comprensibile.
b) In linea teorica si, le lettere possono diventare tante, ma anche li diciamo che si potrebbe risolvere con relativamente poco sforzo.
c) I livelli anche qui, in linea teorica, possono raggiungere profondità considerevoli. Nel file che ho davanti, ci si limita a 4, ma al momento non saprei che dire e nel dubbio dico si.
a) I numeri che sono legati alla lettera non sono un gran problema. Nella situazione reale sono salvati in un'altra colonna e quindi alla mia lettera ci lego il numero che trovo nell'altra colonna. Ho messo i numeri negli esempi solo per chiarirmi le idee e rendere la cosa più comprensibile.
Cosa intendi?
Puoi inviare un file di esempio? Senza dati sensibili?
Riguardo alle domande che ti ho fatto, avere i limiti o una idea dei limiti aiuta ad impostare il programma. se devo prevedere due lettere o una, se devo prevdere una formattazione dei numeri di un certo tipo, ....
Ciao
Luca
Allora ti ho allegato il file xlsx che contiene i dati e il file .bas da associare al file.
Dopo l'importazione del file .bas lancia la macro "ScompattaDistinteNuovoFormato" che altro non fa che scorrere i fogli e preparare i livelli "A".Il dato numerico associato al nodo te lo trovi nella colonna B. Dopodiché, sempre nello stesso file la macro che si chiama "GestioneSubLivello" dove ho iniziato a far qualcosa...C'è un'istruzione " For I = RangeLimitUp To RangeLimitDw" che scrolla il Range fra due livelli A.
Vedi se ti può essere utile.
Allegati:
You must be logged in to view attached files.Ciao Luca...scusa per le info incomplete. Ti allego il file dati che sto usando ed un file di macro che preparano gli stessi. DOpo aver caricato il file .bas, lancia la macro "ScompattaDistinteNuovoFormato" che prepara le colonne. Nella colonna B ti troverai appunto il numero da legare alla lettera.
Sempre nello stesso file c'è la macro "GestioneSubLivello" in cui ho iniziato a far qualcosa. Ti troverai un ciclo che itera fra due livello A " For I = RangeLimitUp To RangeLimitDw".
Vedi se può esserti utile.
Allegati:
You must be logged in to view attached files.Ciao ci sto lavorando. Ho quasi finito spero Lunedì di ricordarmi.
Ciao
Luca
Questo è un caso interessante e potrebbe diventare anche un articolo per il blog.
Magari vi potesse interessare, si accettano proposte da chiunque...
Scrivete le bozze degli articoli direttamente a redazione@excelvba.it
Non ci sono premi ma la soddisfazione di stuzzicare interesse altrui 🙂
Ciao Ecco una prima proposta.
Siccome l'ho fatta e modificata. Secondo me va migliorata e ottimizzata. infatti il vettore che prevedevo dimutilizzare in un modo el'avevo riempito con un criterio, poi l'ho modificato e in parte non serve.
Accetta lettere multiple (ovvero dopo Z c'è AA,...dopo AA c'è AB, dopo AZ c'è BA,...dopo ZZ c'è AAA...)
ATTENZIONE al momento la macro parte da A2 e prende tutto ciò che c'è sotto e poi SCRIVE NELLA COLONNA A FIANCO.
Option Explicit Sub Livelli() Dim Vettore() Dim NumeroLivelli As Integer Dim NumeroCelle As Integer Dim PrimaCella As Range Dim UltimaCella As Range Dim Intervallo As Range Dim CellaW As Range Dim Index As Integer Dim Index2 As Integer Dim LastLetter As String Dim LetterToUse As String Dim MaxN As Integer Dim NumZeri As String Set PrimaCella = Range("A2") Set UltimaCella = PrimaCella.End(xlDown) Set Intervallo = Range(PrimaCella, UltimaCella) MaxN = 1 LastLetter = "A" NumeroCelle = Intervallo.Count NumeroLivelli = 0 For Each CellaW In Intervallo If CellaW > NumeroLivelli Then NumeroLivelli = CellaW End If Next CellaW ReDim Vettore(0 To NumeroLivelli, 0 To NumeroCelle, 1 To 2) For Index = 1 To NumeroCelle If PrimaCella.Offset(Index - 1, 0) * 1 = 1 Then Vettore(1, 0, 1) = Vettore(1, 0, 1) + 1 Vettore(1, Index, 1) = Vettore(1, 0, 1) Vettore(0, Index, 1) = "A" Vettore(0, Index, 2) = Vettore(1, 0, 1) 'PrintVect (Vettore) If Vettore(1, 0, 1) > MaxN Then MaxN = Vettore(1, 0, 1) End If Else If PrimaCella.Offset(Index - 1, 0) * 1 > PrimaCella.Offset(Index - 2, 0) * 1 Then Vettore(PrimaCella.Offset(Index - 1, 0), 0, 1) = 1 Vettore(PrimaCella.Offset(Index - 1, 0), Index, 1) = 1 LastLetter = LetterPlus1(LastLetter) Vettore(0, Index, 1) = LastLetter Vettore(PrimaCella.Offset(Index - 1, 0), 0, 2) = LastLetter Vettore(0, Index, 2) = 1 'PrintVect (Vettore) ElseIf PrimaCella.Offset(Index - 1, 0) * 1 < PrimaCella.Offset(Index - 2, 0) * 1 Then For Index2 = (PrimaCella.Offset(Index - 1, 0) + 1) To NumeroLivelli Vettore(Index2, 0, 1) = 0 Next Index2 Vettore(PrimaCella.Offset(Index - 1, 0), 0, 1) = Vettore(PrimaCella.Offset(Index - 1, 0), 0, 1) + 1 Vettore(PrimaCella.Offset(Index - 1, 0), Index, 1) = Vettore(PrimaCella.Offset(Index - 1, 0), 0, 1) Vettore(0, Index, 2) = Vettore(PrimaCella.Offset(Index - 1, 0), 0, 1) If Vettore(PrimaCella.Offset(Index - 1, 0), 0, 1) = 0 Then LastLetter = LetterPlus1(LastLetter) LetterToUse = LastLetter Else LetterToUse = Vettore(PrimaCella.Offset(Index - 1, 0), 0, 2) End If Vettore(0, Index, 1) = LetterToUse Vettore(PrimaCella.Offset(Index - 1, 0), 0, 1) = Vettore(PrimaCella.Offset(Index - 1, 0), 0, 1) + 1 If Vettore(PrimaCella.Offset(Index - 1, 0), 0, 1) > MaxN Then MaxN = Vettore(PrimaCella.Offset(Index - 1, 0), 0, 1) End If 'PrintVect (Vettore) Else Vettore(PrimaCella.Offset(Index - 1, 0), 0, 1) = Vettore(PrimaCella.Offset(Index - 1, 0), 0, 1) + 1 Vettore(PrimaCella.Offset(Index - 1, 0), Index, 1) = Vettore(PrimaCella.Offset(Index - 1, 0), 0, 1) 'PrintVect (Vettore) Vettore(0, Index, 1) = LastLetter Vettore(0, Index, 2) = Vettore(PrimaCella.Offset(Index - 1, 0), 0, 1) If Vettore(PrimaCella.Offset(Index - 1, 0), 0, 1) > MaxN Then MaxN = Vettore(PrimaCella.Offset(Index - 1, 0), 0, 1) End If End If End If Next Index 'PrintVect (Vettore) NumZeri = "" For Index = 1 To Len(MaxN) NumZeri = NumZeri & "0" Next Index For Index = 1 To NumeroCelle PrimaCella.Offset(Index - 1, 1) = Vettore(0, Index, 1) & Format(Vettore(0, Index, 2), NumZeri) Next Index End Sub Function LetterPlus1(LetteraIniziale) Dim PosLet As Integer Dim VettoreLet ReDim VettoreLet(1 To Len(LetteraIniziale)) For PosLet = 1 To Len(LetteraIniziale) VettoreLet(PosLet) = Mid(LetteraIniziale, Len(LetteraIniziale) - PosLet + 1, 1) Next PosLet = 1 Do If VettoreLet(PosLet) < "Z" Then VettoreLet(PosLet) = Chr(Asc(VettoreLet(PosLet)) + 1) Exit Do Else VettoreLet(PosLet) = "A" PosLet = PosLet + 1 End If If PosLet > UBound(VettoreLet, 1) Then ReDim Preserve VettoreLet(1 To PosLet) VettoreLet(PosLet) = Chr(Asc("A") - 1) End If Loop LetterPlus1 = "" For PosLet = UBound(VettoreLet, 1) To 1 Step -1 LetterPlus1 = LetterPlus1 & VettoreLet(PosLet) Next End Function
ho fatto girare per prova sul file Esempio-1.xlsx. Si ferma, come giusto, sul primo ciclo For, perchè "CellaW" (che punta al range in colonna A) non contiene un numero ma un testo e non lo puoi confrontare con un numero ("NumeroLivelli"). Probabilmente, presumo, il range "Intervallo" deve puntare alla colonna B ("Level").
Tu su che versione del file hai lavorato?
Buongiorno Luca. Intanto grazie per la risposta. Adesso la sto cercando di analizzare. In realtà la prima difficoltà che incontro è capire su che intervallo stai lavorando. Nel mio esempio, la colonna "A" contiene dati non preparati (ad esempio: 101 - 0.003988.E), le colonne "B" e "C" contengono il dato scomposto. Nella colonna "D" i dati del primo livello. La colonna "E" è quella destinata a contenere il dato del livello elaborato. Nel tuo ciclo:
For Each CellaW In Intervallo If CellaW > NumeroLivelli Then NumeroLivelli = CellaW End If Next CellaW
in realtà non capisco su che dati tu vada ad operare...
Lavoro sulla stessa versione del file. Ma hai caricato il file .bas e lanciato la macro "ScompattaDistinteNuovoFormato"?
Comunque il codice non è male anche se sembra incasinato 🙂 ho fatto qualche aggiustatina perchè si arrabbiava ancora confrontando numeri con testo, e ho poi printato nell'ultima colonna anziché nella terza, ma alla fine mi sembra un risultato coerente con la richiesta iniziale. L'unica piccola pecca è che il livello zero viene indicato con "A01" (sicché alla fine ho due livelli "A01") ma penso che si possa sistemare facilmente.
Ma hai caricato il file .bas e lanciato la macro "ScompattaDistinteNuovoFormato"?
No, ho lanciato "LIvelli" 😀
Adesso mi guardo il codice che hai indicato.
in realtà non capisco su che dati tu vada ad operare...
Nel codice originale della sub Livello, "Intervallo" punta alla colonna A. Ma ho sbagliato io e adesso vado a vedere il codice cui ti riferivi poco fa (è quello su cui Luca ha messo mano?).
Ciao
Non ho lavorato sul tuo file ma su uno che mi ero creato io.
Basta cambiare la riga
Set PrimaCella = Range("A2")
Il mio file parte da A2 e prende tutto ciò che c'è sotto fino alla prima libera
Set UltimaCella = PrimaCella.End(xlDown)
Lavoro sulla stessa versione del file. Ma hai caricato il file .bas e lanciato la macro "ScompattaDistinteNuovoFormato"?
Quello è il tuo codice originale, che Luca ha probabilmente riscritto per venire incontro alla tua richiesta. Quindi non lo guardo neanche visto che lo ha già fatto l'amico Luca 🙂
Ho avuto difficoltà come dicevo sui test che i due Ifs fanno per controllare i valori di PrimaCella. Nel tuo codice viene confrontato un valore numerico con un valore testuale. Ho dovuto correggere così:
If Val(PrimaCella.Offset(Index - 1, 0)) * 1 > Val(PrimaCella.Offset(Index - 2, 0)) * 1 Then
forzando con Val() la traduzione numerica del contenuto indicizzato di PrimaCella. Poi tutto fila liscio con la particolarità del livello zero come ho già accennato. In realtà poi io metterei il risultato in ultima colonna, senza sovrascrivere la descrizione.
For Index = 1 To NumeroCelle PrimaCella.Offset(Index - 1, 11) = Vettore(0, Index, 1) & Format(Vettore(0, Index, 2), NumZeri) Next Index
Comunque complimenti non era facile
Ho risistemato le mie macro per impostare i dati in modo da far girare la macro. Impostando la colonna "B" col livello e lasciando libera la colonna "C", i livelli sono aggiunti correttamente, almeno per quanto riguarda la lettera. Adesso Devo sistemare i numeri che in realtà non sono progressivi ma sono i primi caratteri (quelli preceduti dal "-" ) nella colonna "A". Inoltre ci sono delle lettere che non sono ammesse (ad esempio la "I" e lo "O" come valori iniziali). Avevo pensato un approccio decisamente diverso, lavorando sul range del singolo gruppo, tu @luca hai lavorato sul range interno invece....Complimenti @vecchio frac che dici "sembra incasinato"....mi ci vorranno diversi giorni per capire il meccanismo di "vettore"
Bè dai, è un vettore a tre dimensioni che raccoglie per ogni cella (seconda dimensione) il proprio numero di livello (prima dimensione) e il numero progressivo per livello (terza dimensione). Nel primo elemento della prima dimensione (indice zero) il vettore si ricorda dell'elemento radice per ogni nuova lettera (ogni nuova foglia dell'albero). Complesso ma non complicato e anche ingegnoso.
Ma il risultato che ha raggiunto Luca ti soddisfa o no? perchè dici:
Adesso Devo sistemare i numeri che in realtà non sono progressivi ma sono i primi caratteri (quelli preceduti dal "-" ) nella colonna "A".
In realtà, funziona in parte. Aumentando il livello di complessità dell'albero, ci sono degli errori nel risultato. Ora riuscire a capire dove e perché si verificano con una matrice a tre dimensioni non è semplicissimo. Vediamo se con un esempio riesco a spiegarmi:
Supponiamo questo albero, il risultato che si ottiene ha un errore...
Il livello è sempre il 3, quindi dovrebbe essere una C
-
AutoreArticoli