TOP

VBA-Lección 13.3. Uso de arreglos (Arrays) (Ejercicios)

Para practicar el uso de arreglos, crearemos nuestra propia versión de la macro que usamos para demostrar la ventaja de velocidad de los arreglos, paso a paso...


Aquí está el punto de partida para este ejercicio (verá que el conjunto de datos se ha reducido a 1000 filas):

Aquí puede descargar el archivo de ejemplo Excel: matrices_ejercicio.xls

Objetivo del ejercicio: El procedimiento debe procesar los datos en el conjunto de datos utilizando un bucle y contar el número de respuestas SÍ o NO para cada año y para cada número de cliente (ya sea SÍ o NO, según la elección del usuario) e ingresar esta cantidad en la celda especificada de la hoja de cálculo.

Complete la siguiente macro para guardar datos de la hoja de cálculo "DS" en una matriz:

Sub actualize()
     Dim last_row As Integer
     
     'La última fila del conjunto de datos.
     '...
        
     'Guardar un conjunto de datos en una matriz dinámica
     Dim array_db()
     '...
        
End Sub

Aquí hay una solución de ejemplo:

Sub actualize()
     Dim last_row As Integer
     
     'La última línea de la base de datos.
     last_row = Sheets("DS").Range("A1").End(xlDown).Row

     'Guardar un conjunto de datos en una matriz dinámica
     Dim array_db()
     ReDim array_db(last_row - 2, 2)
     
     For row_number = 2 To last_row
         array_db(row_number - 2, 0) = Sheets("DS").Range("A" & row_number)
         array_db(row_number - 2, 1) = Sheets("DS").Range("B" & row_number)
         array_db(row_number - 2, 2) = Sheets("DS").Range("C" & row_number)
     Next
End Sub

Esto básicamente repite lo que hicimos en la lección anterior...

Pero ahora necesitamos modificar nuestra macro agregando las siguientes acciones:

  • Determinar la elección del usuario ("SÍ" o "NO");
  • Cuente el número de respuestas "SÍ" o "NO" en el conjunto de datos para determinar el tamaño de la matriz (Redim);
  • Guardamos solo aquellas filas del conjunto de datos que contienen las respuestas "SÍ" o "NO" en la matriz (esto significa que no es necesario guardar los datos de la tercera columna).
  • Aquí hay una solución de ejemplo:

    Sub actualize()
         Dim last_row As Integer, search_value As String, insert_row As Integer, value_yes_no As String, rows_number As Integer
         
         'La última línea de la base de datos.
         last_row = Sheets("DS").Range("A1").End(xlDown).Row
    
         'Buscar valor (SI o NO)
         If Sheets("RES").OptionButton_yes.Value = True Then
             search_value = "YES"
         Else
             search_value = "NO"
         End If
         
         'El número de respuestas SÍ o NO
         rows_number = WorksheetFunction.CountIf(Sheets("DS").Range("C2:C" & last_row), search_value)
         
         'Guardar un conjunto de datos en una matriz
         Dim array_db()
         ReDim array_db(rows_number - 1, 1)
    
         insert_row = 0
         
         For row_number = 2 To last_row
             value_yes_no = Sheets("DS").Range("C" & row_number)
             
             If value_yes_no = search_value Then
                 array_db(insert_row, 0) = Sheets("DS").Range("A" & row_number)
                 array_db(insert_row, 1) = Sheets("DS").Range("B" & row_number)
                 insert_row = insert_row + 1
             End If
         Next
    End Sub
    

    La búsqueda por elección del usuario se determina al comienzo del procedimiento mediante el siguiente código:

     'Buscar valor (SI o NO)
     If Sheets("RES").OptionButton_yes.Value = True Then
         search_value = "YES"
     Else
         search_value = "NO"
     End If
    

    Usaremos la función CountIF para determinar el número de respuestas "SÍ" o "NO":

     'El número de respuestas SÍ o NO
     rows_number = WorksheetFunction.CountIf(Sheets("DS").Range("C2:C" & last_row), search_value)
    

    La matriz se ha redimensionado para ajustarse al número de respuestas SÍ o NO y se ha reducido a dos columnas:

    ReDim array_db(rows_number - 1, 1)
    

    Estos datos ahora se almacenarán en la matriz cuando su tercera columna coincida con la selección del usuario:

     'Insertar un número en una matriz
     insert_row = 0
    
     'Procesamiento de conjuntos de datos
     For row_number = 2 To last_row
         'Valor de la columna C (SI o NO)
         value_yes_no = Sheets("DS").Range("C" & row_number)
         
         'Si el valor coincide con la selección del usuario, la cadena se almacena en la matriz
         If value_yes_no = search_value Then
             'Guardar el valor en la columna A
             array_db(insert_row, 0) = Sheets("DS").Range("A" & row_number)
             'Guardando el valor en la columna B
             array_db(insert_row, 1) = Sheets("DS").Range("B" & row_number)
             'Se ha guardado una fila => el número de inserción en la matriz se incrementa en 1
             insert_row = insert_row + 1
         End If
     Next
    

    Nuestra matriz contiene solo los datos que nos interesan.

    Todo lo que queda por hacer es:

  • Procese cada elemento de la tabla en la hoja de trabajo "RES" usando 2 bucles (la misma idea que a la derecha con el tablero de ajedrez);
  • Inserte el número total de ocurrencias en esta hoja para cada año por cada número de cliente para cada celda.
  • Aquí hay una solución de ejemplo:

     'Número de respuestas "SÍ"/"NO"
     For no_years = 2011 To 2026
         For no_client = 1 To 30
             counter = 0
             
             For i = 0 To UBound(array_db)
                 If Year(array_db(i, 0)) = no_years And array_db(i, 1) = no_client Then
                     counter = counter + 1
                 End If
             Next
             
             Cells(no_years - 2009, no_client + 1) = counter
         Next
     Next
    

    Problema resuelto con comentarios explicándolo en detalle:

     'Bucle para cada fila
     For no_years = 2011 To 2026
     
         'Bucle para cada columna
         For no_client = 1 To 30
             'Puesta a cero del contador
             counter = 0
             
             'Procesamiento de matriz
             For i = 0 To UBound(array_db)
                 'Comprobando que la fila de la tabla corresponde al año y número de cliente
                 If Year(array_db(i, 0)) = no_years And array_db(i, 1) = no_client Then
                     'Si el año y el número de cliente coinciden, el contador aumenta en 1
                     counter = counter + 1
                 End If
             Next
             
             'Después de procesar la matriz, el resultado se ingresa en la celda correspondiente
             Cells(no_years - 2009, no_client + 1) = counter
         Next
     Next
    

    Y finalmente, el código para toda nuestra macro:

    Sub actualize()
         Dim last_row As Integer, search_value As String, insert_row As Integer, value_yes_no As String, rows_number As Integer, counter As Integer
         
         'Eliminación de contenido
         Range("B2:AE17").ClearContents
         
         'La última fila en el conjunto de datos.
         last_row = Sheets("DS").Range("A1").End(xlDown).Row
    
         'Buscar valor (SI o NO)
         If Sheets("RES").OptionButton_yes.Value = True Then
             search_value = "YES"
         Else
             search_value = "NO"
         End If
         
         'El número de respuestas SÍ o NO
         rows_number = WorksheetFunction.CountIf(Sheets("DS").Range("C2:C" & last_row), search_value)
         
         'Guardar valores en una matriz
         Dim array_db()
         ReDim array_db(rows_number - 1, 1)
    
         insert_row = 0
         
         For row_number = 2 To last_row
             value_yes_no = Sheets("DS").Range("C" & row_number)
             
             If value_yes_no = search_value Then
                 array_db(insert_row, 0) = Sheets("DS").Range("A" & row_number)
                 array_db(insert_row, 1) = Sheets("DS").Range("B" & row_number)
                 insert_row = insert_row + 1
             End If
         Next
         
         'Contando respuestas SÍ o NO
         For no_years = 2011 To 2026
             For no_client = 1 To 30
                 counter = 0
                 
                 For i = 0 To UBound(array_db)
                     If Year(array_db(i, 0)) = no_years And array_db(i, 1) = no_client Then
                         counter = counter + 1
                     End If
                 Next
                 Cells(no_years - 2009, no_client + 1) = counter
             Next
         Next
    End Sub
    

    Aquí puede descargar el archivo de ejemplo Excel: matrices_ejercicio_completado.xls