Programación General > Visual Basic para principiantes

 Funcion para Saber si Un Arreglo Esta Vacio

<< < (3/4) > >>

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

[0] Índice de Mensajes

[#] Página Siguiente

[*] Página Anterior

Ir a la versión completa