Snellire cicli for annidati



  • Snellire cicli for annidati
    di Nico (utente non iscritto) data: 23/03/2017 10:53:18

    Buongiorno,
    Scusate il titolo ma non è di facile spiegazione.
    Vi pongo il mio problema.

    Ho un foglio con una serie di nomi a cui saranno associati delle somme di valori. Ho bisogno di mantenere nomi (e somme) separati in 4 gruppi. Per cui ho nome-somma accoppiati rispettivamente nelle colonne 3-6, 9-12, 15-18, 21-24), a partire dalla riga 3 fino alla 27.
    Di fatto ho 4 gruppi nome-somma da 25 righe ciascuno.

    Nei fogli seguenti (dal foglio 7 in avanti) eseguo dei calcoli e funzioni, per cui mi troverò, random nei vari fogli, solo alcuni dei nomi di cui al primo foglio a cui è associato un valore nella colonna a fianco (ovviamente ho necessità di lasciare i fogli separati).

    L'obiettivo è far sì che nel primo foglio compaia la somma di tutti i valori corrispondenti ai nomi, in tutti i fogli compilati.

    Ho fatto un codice che posto sotto che funziona, ma come vedrete è troppo lunga la sua elaborazione.

    Di fatto creo una matrice di nomi con due cicli For, associo il nome corrente ad una variabile "a" e per ogni foglio (terzo ciclo For), vado a cercare nel range "scritto" il nome corrente.
    Se c'è, sommo il valore corrispondente (posto nella colonna a fianco) ad un'altra matrice (valori), che a sua volta riporta la somma dei fogli precedenti (per quel nome corrente).
    Infine questa somma viene riportata nella giusta posizione del primo foglio.

    Avendo 4 colonne (i gruppi), 25 righe e (ad ora) 47 fogli di conti, capite che vengono fuori 4700 iterazioni.

    C'è una maniera per snellire il tempo di calcolo?



    Grazie!
     
    Sub SingoloMat()
    
    Dim CL As Object
    Dim a As String
    Dim i, k, j As Integer
    Dim nomi(25, 4) As String
    Dim valori(25, 4) As Integer
    
    'Colonne su J
    'Colonne nomi: 3, 9, 15, 21
    'Colonne valori: 6, 12, 18, 24
    'Righe k dalla 3 alla 27
    
    For j = 0 To 3
        For k = 0 To 24
        Sheets("UNO").Select
        nomi(k, j) = Cells(3 + k, (6 * j) + 3).Text    'assegno il nome nella matrice
        a = nomi(k, j)
    
        For i = 7 To (Sheets.Count)
                Set zona = Worksheets(i).UsedRange
                For Each CL In zona                      'ciclo di ricerca in ogni cella dell'area "zona"
                  If CL.Value = a Then
                    CL.Select
                    ActiveCell.Offset(0, 1).Select
                    valori(k, j) = valori(k, j) + ActiveCell.Value
                 End If
               Next
    
          Next
       Sheets("UNO").Cells(3 + k, (6 * j) + 6).Value = valori(k, j)
       Next
    Next
    
     Sheets("UNO").Select
    End Sub
    



  • di Luca73 data: 23/03/2017 11:13:46

    Ciao
    a) 4700 iterazioni non sono una gran cosa per excel.
    b) una volta trovato un certo nome nella Zona ce ne sono altri? se no puoi uscire dal ciclo con un exit for
    c) non selezionare le celle, referenziale

    Inoltre all'inizio agggiungi
    all'inizio
    With Application
    .ScreenUpdating = False
    .EnableEvents = False
    .Calculation = xlCalculationManual
    End With

    alla fine
    '<--- riattivo lo schermo, gli eventi e imposto nuovamente il calcolo in automatico --->
    With Application
    .ScreenUpdating = True
    .EnableEvents = True
    .Calculation = xlCalculationAutomatic
    End With
     
    If CL.Value = a Then
                    CL.Select
                    ActiveCell.Offset(0, 1).Select
                    valori(k, j) = valori(k, j) + ActiveCell.Value
                 End If
    
    DIVENTA
    
    If CL.Value = a Then
       valori(k, j) = valori(k, j) + CL.Offset(0, 1).Value
    End If
    
    
    Sub SingoloMat()
    
    Dim CL As Object
    Dim a As String
    Dim i, k, j As Integer
    Dim nomi(25, 4) As String
    Dim valori(25, 4) As Integer
    With Application
          .ScreenUpdating = False
          .EnableEvents = False
          .Calculation = xlCalculationManual
    End With
    
    For j = 0 To 3
        For k = 0 To 24
            nomi(k, j) = Sheets("UNO").Cells(3 + k, (6 * j) + 3).Text    'assegno il nome nella matrice
            a = nomi(k, j)
            For i = 7 To (Sheets.Count)
                Set zona = Worksheets(i).UsedRange
                For Each CL In zona                      'ciclo di ricerca in ogni cella dell'area "zona"
                    If CL.Value = a Then
                        valori(k, j) = valori(k, j) + CL.Offset(0, 1).Value
                        'Exit For  <= se applicabile ovvero cerca un solo valore
                    End If
                Next CL
            Next i
            Sheets("UNO").Cells(3 + k, (6 * j) + 6).Value = valori(k, j)
        Next k
    Next j
    With Application
        .ScreenUpdating = True
        .EnableEvents = True
        .Calculation = xlCalculationAutomatic
    End With
    End Sub
    
    






  • di Nico (utente non iscritto) data: 23/03/2017 11:31:54

    Grazie mille per i suggerimenti Luca73, effettivamente molto meglio così!

    Effettivamente il nome non si ripete nel singolo foglio per cui posso uscire dal ciclo CL una volta individuato, non ci avevo pensato mannaggia a me...

    Ancora grazie
    Nico