Programación General > Visual Basic para principiantes
¿Cómo redimensionar una matriz dentro de otra matriz?
deaven:
Hola.
Tengo un problema en Visual Basic 6, quisiera ver si alguién me pdría echar una mano.
Según yo, el siguiente código sí debería de trabajar en VB6 (El código sí trabaja bien en Visual Basic 2008)
Private Sub Matrices()
Dim hola()
Dim Matr()
ReDim Preserve hola(20)
ReDim Matr(2)
hola(20) = Matr
hola(20)(0) = "como"
ReDim Preserve hola(20)(1)
End Sub
Al ejecutar el código en VB6, me da error de sintaxis en "ReDim Preserve hola(20)(1)" ¿Cuál podría ser el problema?, ¿Hay alguna solución?
m0skit0:
Usa las etiquetas de código (qué cansinos sois...) -_-
Declara el tipo de las variables <_<
--- Código: Visual Basic ---Type tColumnas Columnas() As IntegerEnd Type Dim Filas() as tColumnasDim i As Integer '20 filas 0 columnasReDim Preserve Filas(20) '20 columnas sólo en la fila 20ReDim Preserve Filas(20).Columnas(20) '20 columnas en las 20 filasFor i=0 to 20 ReDim Preserve Filas(i).Columnas(20)Next i No lo he probado, pero debería funcionar.
deaven:
Si k funciona, no sabía k se podía hacer eso.
Mil gracias m0skit0, me ahorraste mucho tiempo. :rolleyes:
Nebire:
La solución que te presenta Moskito tiene una ventaja y una desventaja.
La ventaja es que te permite redimensionar FACILMENTE .
La desventaja es que el cálculo de las direcciones es más lento ya que es una matriz dentro de una matriz de estructuras. tiene que calcular la dirección del índice de la matriz luego de la estructura y luego de la otra matriz.
El modo en que VB6 redimensiona las demás dimensiones es del siguiente modo:
--- Código: Visual Basic --- dim k() ' declarar 3 dimensionesredim k(0 to 99, 0 to 99, 0 to 99) ' 3 dimensiones = 100 * 100 * 100 elementos 1millón. ' redimensionar la marizredim preserve k(100,100, 120) ' al utilizar preserve sólo se puede alterar la última dimensión y no permite añadir ni quitar dimensiones. Para hacer esto hay que crear una nueva matriz con las diemnsiones requeridas y pasar desde la primera hacia esta lo que deseemos, luego asignar a la primera el valor de esta.
Puede interesar ver algunas consideraciones en torno alas matrices dinámicas, estáticas y el uso de preserve las matrices variant son otro caso que ahora no comentamos
--- Código: Visual Basic --- ' usando una matriz dinámica Dim k() As Byte ' esto es perfectamente válido ReDim k(0 To 99, 0 To 99, 0 To 99) ReDim Preserve k(0 To 99, 0 To 99, 0 To 120) ReDim Preserve k(0 To 99, 0 To 99, 0 To 20) ' esto no es válido ReDim Preserve k(0 To 99, 0 To 99, 0 To 99, 0 To 2) ' añadir dimensiones ReDim Preserve k(0 To 99, 0 To 99) ' quitar dimensiones ReDim Preserve k(0 To 99, 0 To 120, 0 To 99) ' variar tamaño de dimensiones anteriores a la última ' pero sin preserve (lo anterior) si es válido, porque se borra toda la información de la matriz y se crea de nuevo, por eso se llama dinámica ReDim k(0 To 99, 0 To 99, 0 To 99, 0 To 2) ' añadir dimensiones ReDim k(0 To 99, 0 To 99) ' quitar dimensiones ReDim k(0 To 99, 0 To 120, 0 To 99) ' variar tamaño de dimensiones anteriores a la última ' usando una matriz estática Dim W(0 To 99, 0 To 99) As Byte ' no se puede redimensionar de ninguna manera, W es una matriz estática, durante su vida no puede tener otras dimensiones que las declaradas, es una matriz de dimensiones 'constante' ReDim Preserve W(0 To 99, 0 To 120) ' en cuanto entre en la función marcará el error (early binding), comentar la línea entonces ReDim W(0 To 99, 0 To 120) ' en cuanto entre en la función marcará el error (early binding), comentar la línea entonces w(45, 45, 45) = 122 ' marcará que las dimensiones no corresponden... en cuanto entre en la función (early binding) k(45, 45, 45, 45, 45, 45) = 122 ' aquí sólo notará el error cuando llegue a su ejecución. (late binding) ' esto no da error, porque al ser estática con erase lo que hace es borrar la matriz y reconstruirla nuevamente (equivale a borrar su contenido a cero, una reiniciación de la misma) Erase W W(45, 45) = 122 ' una matriz dinámica borrada equivale a no estar inicializada es como cuando sólo se había declarado Dim k() As Byte ' aquí dará error, el error es que no tiene dimensiones declaradas. Erase k k(45, 45, 45) = 122
ejemplo de un redimensionado de una matriz dinámica en una dimensión anterior:
Supongamos una matriz que guarda meses y días en forma de matriz...
--- Código: Visual Basic --- dim año() as boolean redim año(1 to 12, 1 to 7) ' primera semana de cada mes ' asignar valores... for mes= 1 to 12 for dia=1 to 7 año(m,s)=true next next
Después de esto supongamos que tenemos otro problema similar pero que en vez de usar sólo la 1ª semana de cada mes queremos usar las 4 semanas completas del mes para redimensionar la matriz
podríamos considerarlo como 28 días en vez de 7
--- Código: Visual Basic --- redim año(1 to 12, 1 to 28) 'las 4 semanas de cada mes ' asignar valores... for mes= 1 to 12 for dia=8 to 28 año(m,s)=true next next
pero puede que queramos trabajar utilizando una dimensión más para referirnos a cada semana por separado dado que no podemos hacer un preserve y a la vez variar el número de dimensiones tenemos que utilizar una mtriz de intercambio...
--- Código: Visual Basic --- dim prov(1 to 12, 1 to 4, 1 to 7) ' declaramos la matriz provisional que es como debería quedar la matriz original ' asignamos los datos actuales ' hacemos un equivalente al preserve pero trasladando datos donde corresponda for mes= 1 to 12 for dias= 1to 7 prov(mes,1,dias)= año(mes,dias) next next ' si queremos reasignar los datos nuevos... for mes= 1 to 12 for semana= 2 to 4 for dias= 1to 7 prov(mes,semana,dias)= true next next next ' finalmente la matriz se la entregamos a la matriz de uso público aquí prov es privada para la función cuyo cometido exclusivo (de la función) podría ser éste año= prov ' año toma tanto los datos como las diemsniones,
Esto (lo anterior) supone una molestia porque se necesita crear una función específicamente para esto, por eso la solución que expone Moskito debe tenerse en consideración.
Otra solución es la que te presento a continuación, que trata de usar una matriz dinámica unidimensional oculta, el sistema utilizado para localizar el valor es similar a como se hace a bajo nivel, pero de cara a usarlo repetidamente es más cómodo que utilizar una matriz de varias dimensiones que además se prestan mucho a confusión. De hecho cuand se usan más de 2 dimensiones interesa más tener un estructura de este tipo. De hecho con poco más lo puedes convertir en una clase
Redimensionar la matriz equivale a asignar a la propiedad año un nuevo valor. Y tomar el valor de ún índice equivale a usar la propiedad DiaX donde se le pasan los indices de cada dimensión mes,semana y dia que se utiliza para calcular el índice de la matriz valores.
--- Código: Visual Basic --- public type infoAño Meses as byte Semanas as byte Dias as byte end type private p_Año as infoAño ' la matriz es unidimensional, es ella quien guarda todos los elementos y somos nosotros quienes proveemos la dirección de cada elemento. Private valores() as boolean ' pregunta por los índices que tiene cada 'dimensión' friend property get Año( optional preservar as boolean=false) as infoAño año= p_año end property ' redimensiona la matriz privada con los nuevos valores de las diemsniones friend property let Año( optional preservar as boolean=false, byref nAño as infoAño) if preservar=false then redim valores(0 to (nAño.meses * nAño.seamanas * nAño.dias ) - 1) else ' invocar a una función que resguarde valores actuales .. queda como ejercicio para el interesado, ' esto puede ser en parte similar a la función del código anterior pero debería usarse un select case para ver que 'dimensiones' son las que varían end if p_año= nAño next public property get DiaX(byval Mes as byte, byval Semana as byte, byval Dia as byte) as boolean diaX= valores((mes-1) * 28) + ((semana-1) * 7) + dia - 1) end property public property let DiaX(byval Mes as byte, byval Semana as byte, byval Dia as byte, byval v as boolean) valores((mes-1) * 28) + ((semana-1) * 7) + dia - 1)= v end property ' sobrecarga, llama a la propiedad, pero recibe como parámetro una estructura.... friend function GetDiaX(byref fecha as infoAño) as boolean GetDiaX= diax(fecha.meses, fecha.semanas,fecha.dias) end function friend sub SetDiaX(byref fecha as infoAño) diax=(fecha.meses, fecha.semanas,fecha.dias) end function nota: el código está escrito directamente quizás se haya escapado algún error
nota2: para los que se toman todas las palabras al pie de la letra... el hecho de utilizar variables llamadas mes, semana ,etc... sólo tiene por objeto no perderse en detalles por trabajar con objetos de naturaleza abstracta, si un ejemplo se explica con algo conocido resulta más fácil ver lo que se quiere explicar sin perderse en la naturaleza del objeto de ejemplo si fuera bastracto, por tanto en ejemplos de este tipo sólo interesa la didáctica. Como todo el mundo sabe como el año no tiene períodos regulares lo que supuestamente se utiliza para el cálculo en el ejemplo no tiene nada que ver con el cálculo real de fechas, si a alguien le confunde, sustituye mes, semana, dia y año por nombres cualquiera de variables..
En todo caso haz unas pruebas de rendimiento con cada método si tienes que hacer un uso intensivo para decidir el que más convenga... si no hay un uso intensivo y por tanto el rendimiento no es decisivo, elige el que más cómodo te resulte.
deaven:
Hola Nebire, muchas gracias x tu respuesta
Exactamente estoy viendo lo k comentas del rendimiento de lo k Moskito me hizo el favor de contestarme.
Para el programa k estoy optimizando y ampliando, es muy importante la velocidad, y como éste usa, en buena medida, muchas matrices (algunas matrices se redimensionan miles de veces, x cuestión de compromiso entre velocidad y memoria usada), es imprescindible k escoja el sistema más veloz.
Muy interesante tu explicación k das del funcionamiento de las matrices
El método de sustitución del uso de matrices k me comentas me parece también muy interesante. Estoy haciendo las pruebas de rendimiento k comentas tanto de lo comentado por Moskito como lo comentado x tí. Si alguno de esos métodos son más rápidos k los k actualmente uso, sin duda los implementaré, especialmente en la ampliación del programa, porque para lo ya escrito del programa me sería algo tardado, x k son miles de líneas de código k se tendrían k modificar.
Para k te des una idea mas amplía, pongo la sub, k mando llamar para redimensionar varios tipos de matriz al doble de índices k tenga su dimensión última. Indicando entre líneas de asteríscos los puntos k quiero optimizar .
'Nebire, nuevamente gracias x el valioso tiempo k te tomas en contestar, analizaré el código k escribiste a fondo.
Saludos
--- Código: Visual Basic --- 'Redimensiona los índices de la matriz al doble de su valor actual, preservando sus valores originales (incluye matrices de una dimensión, 2 dimensiones y matrices dentro 'de matrices)Public Sub RedimMat(NombreMatriz As String, Optional Nivel1, Optional Nivel2, Optional LlenarLosNuevosIndicesConElSigValor As Boolean = False, _ Optional ValorAIntroducirEnLosIndicesDeLaMat As Variant = SinVal)'ENTRADAS'1)NombreMatriz indica el nombre de la matriz a redimensionar'2)Nivel1 = Primer nivel de profundidad de matriz'3)Nivel2 = Segundo nivel de profundidad de matriz'4)ValorAIntroducirEnLosIndicesDeLaMat = Es el valor k se va a introducir en los nuevos índices redimensionados de la matriz (en caso de k LlenarLosNuevosIndicesConElSigValor '= True'5)LlenarLosNuevosIndicesConElSigValor = Bandera para utilizar ValorAIntroducirEnLosIndicesDeLaMat o no utilizarla 'SALIDAS'1)La matriz indicada x el NombreMatriz, ya redimensionada al doble Static MatRedimMatTemporal As VariantDim EmpezarALlenarConElValor3APartirDeEsteNumeroDim NumeroLlenando As Long Select Case NombreMatriz 'Matrices con 1 dimensión Case "CPsValores" ReDim Preserve CPsValores(LBound(CPsValores) To UBound(CPsValores) + (UBound(CPsValores) _ - LBound(CPsValores) + 1)) Case "MatDendDsAMover" ReDim Preserve MatDendDsAMover(LBound(MatDendDsAMover) To UBound(MatDendDsAMover) + (UBound(MatDendDsAMover) _ - LBound(MatDendDsAMover) + 1)) Case "MatrizDeCamSeñales" ReDim Preserve MatrizDeCamSeñales(LBound(MatrizDeCamSeñales) To UBound(MatrizDeCamSeñales) + (UBound(MatrizDeCamSeñales) _ - LBound(MatrizDeCamSeñales) + 1)) Case "PoblacsPendientes" ReDim Preserve PoblacsPendientes(LBound(PoblacsPendientes) To UBound(PoblacsPendientes) + (UBound(PoblacsPendientes) - LBound(PoblacsPendientes) + 1)) Case "C" ReDim Preserve C(LBound(C) To UBound(C) + (UBound(C) - LBound(C) + 1)) Case "MatCamSeñalesDeCaseta" ReDim Preserve MatCamSeñalesDeCaseta(LBound(MatCamSeñalesDeCaseta) To UBound(MatCamSeñalesDeCaseta) + (UBound(MatCamSeñalesDeCaseta) - LBound(MatCamSeñalesDeCaseta) + 1)) Case "MatDeCaHisYCaMas" ReDim Preserve MatDeCaHisYCaMas(LBound(MatDeCaHisYCaMas) To UBound(MatDeCaHisYCaMas) + (UBound(MatDeCaHisYCaMas) - LBound(MatDeCaHisYCaMas) + 1)) '********************************************************************* 'PUNTO K QUISIERA OPTIMIZAR 'Matrices q a fuerzas se tienen q copiar a una matriz individual, porque la instrucción Redim no permite redimensionarlas directamente, porque 'son matrices q están dentro de otra matriz, y vb6 no la reconoce como tal (visual basic 2008 sí la reconoce) Case "C() () " MatRedimMatTemporal = C(Nivel1)(Nivel2) If LlenarLosNuevosIndicesConElSigValor = True Then EmpezarALlenarConElValor3APartirDeEsteNumero = UBound(MatRedimMatTemporal) + 1 ReDim Preserve MatRedimMatTemporal(LBound(MatRedimMatTemporal) To UBound(MatRedimMatTemporal) + (UBound(MatRedimMatTemporal) _ - LBound(MatRedimMatTemporal) + 1)) If LlenarLosNuevosIndicesConElSigValor = True Then For NumeroLlenando = EmpezarALlenarConElValor3APartirDeEsteNumero To UBound(MatRedimMatTemporal) MatRedimMatTemporal(NumeroLlenando) = ValorAIntroducirEnLosIndicesDeLaMat Next End If C(Nivel1)(Nivel2) = MatRedimMatTemporal Case "CpsValores() () " MatRedimMatTemporal = CPsValores(Nivel1)(Nivel2) If LlenarLosNuevosIndicesConElSigValor = True Then EmpezarALlenarConElValor3APartirDeEsteNumero = UBound(MatRedimMatTemporal) + 1 ReDim Preserve MatRedimMatTemporal(LBound(MatRedimMatTemporal) To UBound(MatRedimMatTemporal) + (UBound(MatRedimMatTemporal) _ - LBound(MatRedimMatTemporal) + 1)) If LlenarLosNuevosIndicesConElSigValor = True Then For NumeroLlenando = EmpezarALlenarConElValor3APartirDeEsteNumero To UBound(MatRedimMatTemporal) MatRedimMatTemporal(NumeroLlenando) = ValorAIntroducirEnLosIndicesDeLaMat Next End If CPsValores(Nivel1)(Nivel2) = MatRedimMatTemporal'*********************************************************************** 'Matrices con 2 dimensiones Case "MatCamLlavesTratadas" ReDim Preserve MatCamLlavesTratadas(LBound(MatCamLlavesTratadas, 1) To UBound(MatCamLlavesTratadas, 1), _ LBound(MatCamLlavesTratadas, 2) To UBound(MatCamLlavesTratadas, 2) + (UBound(MatCamLlavesTratadas, 2) - LBound(MatCamLlavesTratadas, 2) + 1)) Case "MatSeparadoresDeConceptos" ReDim Preserve MatSeparadoresDeConceptos(LBound(MatSeparadoresDeConceptos, 1) To UBound(MatSeparadoresDeConceptos, 1), _ LBound(MatSeparadoresDeConceptos, 2) To UBound(MatSeparadoresDeConceptos, 2) + (UBound(MatSeparadoresDeConceptos, 2) - LBound(MatSeparadoresDeConceptos, 2) + 1)) Case "MatrizDeAccionesEnVisio" ReDim Preserve MatrizDeAccionesEnVisio(LBound(MatrizDeAccionesEnVisio, 1) To UBound(MatrizDeAccionesEnVisio, 1), _ LBound(MatrizDeAccionesEnVisio, 2) To UBound(MatrizDeAccionesEnVisio, 2) + (UBound(MatrizDeAccionesEnVisio, 2) - LBound(MatrizDeAccionesEnVisio, 2) + 1)) Case "MatDeCaHis" ReDim Preserve MatDeCaHis(LBound(MatDeCaHis, 1) To UBound(MatDeCaHis, 1), _ LBound(MatDeCaHis, 2) To UBound(MatDeCaHis, 2) + (UBound(MatDeCaHis, 2) - LBound(MatDeCaHis, 2) + 1)) Case Else ErrorCritico ("La Matriz se tiene que redimensionar antes de continuar"), -1: Debug.Assert Seguir: Ending 'Si no encontré el NombreMatriz, saca un error y ya no puedo 'continuar hasta k solucione el error. End Select NombreMatriz = "" End Sub
Navegación
[#] Página Siguiente
Ir a la versión completa