Programación General > Visual Basic para principiantes
Funcion para Saber si Un Arreglo Esta Vacio
m0skit0:
Y para respaldar mi teoría, aquí te pongo un ejemplo, acompañado por el código fuente si quieres comprobarlo:
--- Código: Visual Basic --- Private Sub Funcion1() Dim Lista As Variant Dim a As Integer Dim i As Long If Not IsArray(Lista) Then Lista = Array() End If a = UBound(Lista) ReDim Preserve Lista(a + 1) For i = 1 To 100000 ReDim Preserve Lista(UBound(Lista) + 1) Lista(i) = 1 Next iEnd Sub
--- Código: Visual Basic --- Private Sub Funcion2() Dim Lista As tTipo Dim a As Integer Dim i As Long Lista.NElementos = 0 a = Lista.NElementos ReDim Preserve Lista.Lista(a + 1) For i = 1 To 100000 Lista.NElementos = Lista.NElementos + 1 ReDim Preserve Lista.Lista(Lista.NElementos) Lista.Lista(i) = 1 Next iEnd Sub
Tiempos de ejecución:
Funcion1() -> 1612 mseg.
Funcion2() -> 69 mseg.
23 veces más rápido con el método que he comentado.
Aquí te adjunto el proyecto:
[attachment=0:dgcyi09s]Prueba Variant vs Registro.7z[/attachment:dgcyi09s]
m0skit0:
Y aparte, según MSDN:
--- Citar ---Una variable Variant puede contener una matriz de cualquier tipo, excepto cadenas de longitud fija y tipos definidos por el usuario.
--- Fin de la cita ---
Nebire:
--- Cita de: "m0skit0" --- Bueno, aquí cada uno tiene su forma de resolver los problemas. También veo que no te atienes a razones, puesto que te repito que una variable de tipo Variant (y no hablemos de un array de Variant) es la más lenta
3. Variant es una muy mala idea de Microsoft, cualquier programador con experiencia te lo puede confirmar. ¿Quién usa VARIANT en C++? Nadie, por algo será.
--- Fin de la cita ---
No sé que pensar... Puedes decirme donde he dicho yo que una Variant sea más rápido que usar otro tipo de variable ????. Es que no haces más que dar vueltas a lo mismo, quizás sea por eso de ''para respaldar mi teoría'' .
Parece que la conversación quieres derivarla hacia una afirmación que yo nunca he dicho, porque yo no digo (ni nunca he afirnado) que una variant sea más rápido que un un tipo de datos 'genérico'. Eso creo que todo el mundo lo tiene muy claro. Ni tampoco he dicho que usar una variant requiera menos memoria. Esto son cosas que ni siquiera tratan el tema que pronuncia el hilo... que por si lo has olvidado era: ''Funcion para Saber si Un Arreglo Esta Vacio''
Por lo mismo el código que expones no sirve de ejemplo para lo que se pretende explicar. Está inflado, te explico porqué: Lo que compruebas miles de veces es el uso de una matriz variant frente a una matriz genérica, y no es el uso de uno ú otro tipo que lo que debatimos desde un principio sino conocer el tamaño de una matriz y saber si está inicializada o no, esto y sólo esto es lo que debe probarse miles de veces, tu sólo lo pruebas 1 vez en tu código... probar otra cosa es meter en el saco ' lo que hay alrededor' . Es como entrar a una tienda, mirar cien cosas y señalar sólo una para comprar, pero a la hora de pagar el tipo te ha metido todo lo que has mirado, es claro que sólo vas a pagar y te vas a llevar aquello que decidiste, nada más, del mismo modo tu has metido en el saco todo lo que te ha parecido no sé si por descuido o para ''respaldar mi teoría'' , creo que lo que señalas en tu código no es el objeto que yo presenté más arriba pero tú no paras de darle vueltas... cuanto esto sucede en una tienda, uno simplemente se va a otra tienda donde el vendedor no te dé la paliza con nada que no hayas indicado.
De hecho soy enemigo acérrimo del variant pero hay excepciones y reconozco que en dichas excepciones es donde las utilizo porque usar un método alternativo resulta engorroso, largo o incómodo
Recientemente he construído un ActiveX que recibe 1 entre 4 propuestas, cada una de ellas trata un panel distinto, la función de entrada es una. la misma para los 4 cometidos sin embargo la devolución de datos es diferente en cada caso. Es un variant lo que utilizo para devolver el dato, de otro modo tendría que repetir bastante código y/o utilizar funciones distintas. El que llama sabe que dato espera por tanto no existe complicación ya que esuna y solo una función de entrada para usarlo resulta más sencillo de usar y recordar y la conversión en la devolución del dato es simplemente despreciable. En fin cada uno sabrá donde y cuando utilizar un variant, negarlo es simplemente cerrar lo ojos.
Yo desde hace muchos años veo una variant como una cerveza, cuando lo normal es beber agua, de tanto en tanto una cerveza resultará más gratificante que un vaso de agua, claro que su abuso ciertamente no es nada bueno y no debe ser lo habitual... pero no hay porqué desterrarla si uno sabe usarla cuando la ocasión lo requiere.
--- Cita de: "m0skit0" ---Aqui te dejo un enlace al tipo Variant y las excepciones para usarlo. Un saludo.
--- Fin de la cita ---
Gracias por tomarte la molestia, pero no era necesario, desde que existe internet, he leído miles de páginas... en cualquier caso las ayudas y manuales que trae el programa son bastante más profusas y profundas que la inmensa mayoría de páginas que se pueden ver en internet... MSDN después de todo nació posiblemente más como un método de ahorrarse distribuir manuales que otra cosa VB 60 empresarial se acompaña de 2 CD de MSDN. Se da el caso de que muchas páginas de internet tienen aún (incluso en VB 2008) el mismo contenido que venían en los CD hace 10 años.
Para poner un ejemplo y probarlo debes ceñirte a un bucle que llama a una función y que comprueba si el array está declarado, esto es devuelva el límite del array ... quedamos en que por un lado se usó 'on Error' y por otro un registro que debe actualizarse y finalmente el método que yo os propuse... es eso y sólo eso lo que debe probarse no el trabajo, comprobar el límite y devolver su valor desde la función, cualquierm otro manejo de Variant nunca se ha insinuado...
Te pongo un código que hace una comparativa entre los métodos presentados a lo largo de la conversación, te resumo brevemente como se ha hecho la comparativa y el resultado, luego lo puede probar cualquiera.
la comparativa son 2 bucles anidados uno de 10 veces y otro interno de hasta 30.000 veces (un control scroll indica la cantidad), en el caso se ha rastreado el límite de la matriz por tanto 300.000 veces
los 3 métodos empleados son: el 'On Error' que exponía nuestro amigo CpMario y que es el más habitual para casos puntuales, el método del 'Registro' de nuestro amigo Moskito y mi método usando un variant... la matriz usada ha sido de enteros, que al caso no tiene mayor relevancia, ya que para todos los casos este dato no varía. El equipo con el que se ha realizado el cálculo es un pentium 4 a 1500Mhz.
Se han calculado 2 respuestas para el resultado una el tiempo empleado y otra la memoria constante en juego. la matriz finalmente fue de 30.000 elementos
--- Código: Text --- Tiempo 'On error' : 0'466875 Memoria en bytes: 60.000Tiempo 'Registro' : 0'375 Memoria en bytes: 180.000Tiempo 'Variant' : 1'17175 Memoria en bytes: 60.000
Las conclusiones (una vez que veais el código) son claras, 'on error' es algo más de 2 veces de rápido que 'Variant', y 'Registro' algo menos de 3 veces que 'Variant' sin embargo 'Variant' provee sólución para todoas las matrices es decir basta con una sola función para chequear 'integer', 'string' ,'byte', 'long'....
1 _) 'On Error' en cambio requiere una función por cada tipo distinto y si se origina otro tipo de error diferente al de matriz no inicializada requiere tratarlo en la función y luego a la devolución diferenciarlo.
2 _) 'Registro' triplica la memoria usada para un integer (otros tipos varían la proporción en función de los bytes del tipo de dato), pero igualmente requiere un registro por cada tipo y matriz, además requiere actualizar contínuamente el contador no sólo cuando redimensionamos explícitamente si no también cuando lo hacemos a través de funciones y otras asignaciones, por ejemplo si tengo un registro 'A' y voy a filtrar la matriz de 'A' por una función por ejemplo A.miarray= filtrar_Nombres(a.miarray), si filtrar_nombres recibe como parámetro una matriz y devuelve una matriz requiere comprobar nuevamente cuantos elementos tiene ahora, lo que requiere modificar todas las funciones para recibir el 'registro' en vez de un array para que en su caso actualice adecuadamente dicho valor, y esto será posible tanto en cuanto todas las funciones sean escritas por nosotros si las funciones son ajenas el contador se queda huérfano y por tanto habrá que recurrir a 'onerror' o a 'variant' para actualizarlo, en definitiva, cojea...
3 _) En este sentido el método 'Variant' es universal más breve y sencillo y si vemos la cantidad de tiempo empleado después de 300.000 comprobaciones es simplemente despreciable (3,9041666666666666666666666666667e-6 por cada iteración completa del bucle).
Ahora eso si, en lo que estoy de acuerdo con moskito es en eso de '''Bueno, aquí cada uno tiene su forma de resolver los problemas''', por lo que cada cual elija el método que prefiera.
Además podrá verse en el código que el manejo de Variant no es tan alegremente que como Moskito se haya imaginado. sino que como ya indiqué en otro mensaje anterior debe realizarse una función de acuerdo a las necesidades que uno pueda tener, los códigos que puse con anterioridad sólo son para demostrar que no daban error como indicaba Moskito, a partir de ahí cada uno puede montarlo como le dé su cabeza...
El código se adjunta en un archivo rar... si hay problemas con algo avisad ...
--- Código: Visual Basic --- ' este proyecto presenta una comparativa con 3 métodos diferentes para' verificar si un array está INICIALIZADO (O NO), y proceder en cada caso' a redimensionarlo o iniciarlo. ' metodo 2 emplea este registro Private Type miRegistro suArray() As Integer contador As Integer End Type Dim suArray() As Integer ' emplean métodos 0 y 1 método ON ERROR Dim miArray ' lo emplea método 1 método VARIANT Dim tuArray As miRegistro ' emplea el método 2 método REGISTRO ' comCalcular es un botón, txttiempo y TxtByte son 2 cajas de texto, frametodo es un Frame que contiene a 3 controles option que representan el método elegido' hscrRep es un scroll horizontal para modificar el número de repeticiones, finalmente hay un label que indica el valor del scroll... Private Sub ComCalcular_Click() Dim t As Single ' para el cálculo del tiempo empleado Dim tamByte As Long ' para el cálculo de la memoria que ocupa Me.TxtTiempo.Text = 0 Me.TxtByte.Text = 0 DoEvents If FraMetodo.Tag = 0 Then ' Método ON ERROR t = Timer For j = 0 To 10 For k = 1 To HScrRep.Value If limiteA(suArray) <> -1 Then ReDim Preserve suArray(0 To UBound(suArray)) suArray(UBound(suArray)) = k Else ReDim suArray(0 To 0) suArray(0) = 0 End If Next Erase suArray Next j TxtTiempo.Text = Timer - t TxtByte.Text = (tamByte + HScrRep.Value) * Len(suArray(0)) ElseIf FraMetodo.Tag = 1 Then ' Método VARIANT t = Timer For j = 0 To 10 For k = 1 To HScrRep.Value 'MsgBox VarType(miArray) If limiteB(miArray) <> -1 Then ReDim Preserve suArray(0 To UBound(suArray)) suArray(UBound(suArray)) = k Else ReDim suArray(0 To 0) suArray(0) = 0 End If miArray = suArray Next Erase suArray Set miArray = Nothing Next j TxtTiempo.Text = Timer - t TxtByte.Text = (tamByte + HScrRep.Value) * Len(suArray(0)) Else ' Método REGISTRO t = Timer For j = 0 To 10 tuArray.contador = -1 For k = 1 To HScrRep.Value If tuArray.contador <> -1 Then tuArray.contador = tuArray.contador + 1 ReDim Preserve tuArray.suArray(0 To tuArray.contador) Else tuArray.contador = 0 ReDim tuArray.suArray(0 To 0) End If tuArray.suArray(tuArray.contador) = k Next Erase tuArray.suArray Next TxtTiempo.Text = Timer - t TxtByte.Text = (tamByte + HScrRep.Value) * Len(tuArray) End If Erase suArray, tuArray.suArrayEnd Sub ' sólo procesa el tipo integer, para otro tipo debe proveerse otra función casi idénticaPublic Function limiteA(matriz() As Integer) As Integer On Local Error GoTo limiteError limiteA = UBound(matriz) Exit Function limiteError: limiteA = -1End Function ' procesa tanto matrices de enteros como de cadenas, bytes, long etc....Public Function limiteB(matriz As Variant) As Integer If Not IsArray(matriz) Then matriz = Array() End If limiteB = UBound(matriz)End Function Private Sub Form_Load() FraMetodo.Tag = 0End Sub Private Sub HScrRep_Change() Me.LabRep.Caption = "Repeticiones: " & HScrRep.ValueEnd Sub Private Sub OptMetodo_Click(Index As Integer) FraMetodo.Tag = IndexEnd Sub
Además para ser puristas (aunque lo que comento a continuación se sobrenetiende) calcular los elementos de una matriz no es usando ubound(matriz) sino usando la fórmula: ubound(matriz) - lbound(matriz) + 1, ya que por ejemplo si declaramos la matriz: dim Hola(-5 to 9) y pedimos ubound(hola) nos devuelve 9 que es el límite superior... pero en fin esto se sobreentiende aunque los novatos suelen tomarlo todo al pie de la letra...
Jimbenit:
La discusión entre Mosquito y Nebire fue muy, muy buena e instructiva (Gracias Moskito y gracias Nebire por brindarnos esa conversación tan instructiva).
Me entretube leyendola, fue muy divertida y llena de ejemplos, muy ilustrativa, pero el novato MArio, quien solicito la ayuda , si entendió lo que ustedes dijeron???
:mellow:
Bueno Saludos , y todos estamos aqui para aprender!!....
--- Código: Text ---Private Sub Form_Load() Dim Nilson As String MsgBox ("Saludos"), , "Nilson Yair"End Sub
Astronald:
No se....., no encontre en internet entonces hice esta funcion
--- Código: Text --- Private Function LimiteArray(ByRef Arreglo As Variant) As Long On Error GoTo SinIniciar LimiteArray = UBound(Arreglo) Exit FunctionSinIniciar: LimiteArray = -1End Function
lo otro es que si redimensionamos con esta funcion la primera es igual a cero
ejemplo,
--- Código: Text --- redim Arreglo(limiteAray(arreglo)+1) si no esta iniciada la inicia en 0
A mi me gusto
Y tampoco me gusta las variables Variat para crear arreglos en esta utilizo una pero solo como referencia para permitir todo tipo de matrices
Navegación
[#] Página Siguiente
[*] Página Anterior
Ir a la versión completa