• Viernes 8 de Noviembre de 2024, 07:00

Autor Tema:  Funcion para Saber si Un Arreglo Esta Vacio  (Leído 26154 veces)

MArio85

  • Miembro activo
  • **
  • Mensajes: 27
    • Ver Perfil
Funcion para Saber si Un Arreglo Esta Vacio
« en: Miércoles 30 de Julio de 2008, 00:23 »
0
Hola, en mi programa utilizo varios arreglos dinamicos los cuales pueden o no ser utilizados por lo que requiero una funcion que me diga si esta vacio o no.
Por ejemplo mi codigo es asi:

Código: Text
  1.  
  2. dim Arreglo() as String
  3.  
  4. If "Condicion" then
  5.       redim preserve Arreglo(i)
  6.       i = i+1
  7. endif
  8.  
  9. for i=0 to ubound(Arreglo)
  10.          "Sentencia"
  11. Next i
  12.  
  13.  

Pero si el arreglo esta vacio es decir nunca se dimensiono me marca el error "Parametro Fuera del Intervalo", He estado utilizando variables bandera para verificar si esta vacio o no, pero supongo que ha de haber una funcion que lo haga.

Gracias

m0skit0

  • Miembro de PLATA
  • *****
  • Mensajes: 2337
  • Nacionalidad: ma
    • Ver Perfil
    • http://fr33kk0mpu73r.blogspot.com/
Re: Funcion para Saber si Un Arreglo Esta Vacio
« Respuesta #1 en: Miércoles 30 de Julio de 2008, 09:33 »
0
La función es UBound(). Míratela en la ayuda de VB6.

cpmario

  • Miembro HIPER activo
  • ****
  • Mensajes: 629
    • Ver Perfil
    • http://www.cpimario.com
Re: Funcion para Saber si Un Arreglo Esta Vacio
« Respuesta #2 en: Miércoles 30 de Julio de 2008, 18:18 »
0
Si el arreglo está vacío la función Ubound también marcará un error.
Debes basarte en la otra variable (la que suma) la i

Por ejemplo:
Código: Text
  1. If i = 0 then
  2.     'El arreglo está vacío
  3. Endif 
  4.  

La alternativa es manejar el error que aparece cuando el arreglo está vacío con On Error

 :comp:

m0skit0

  • Miembro de PLATA
  • *****
  • Mensajes: 2337
  • Nacionalidad: ma
    • Ver Perfil
    • http://fr33kk0mpu73r.blogspot.com/
Re: Funcion para Saber si Un Arreglo Esta Vacio
« Respuesta #3 en: Miércoles 30 de Julio de 2008, 19:04 »
0
Ups, perdón, no había caído en que usabas UBound ya. Jejejejeje, es que el madrugar me deja atontado. -_-

Cita de: "cpmario"
Debes basarte en la otra variable (la que suma) la i


O cpmario es un genio, o yo soy tonto, o esto está mal. Lo que sí puedes usar es el On Error como bien te comenta cpmario. Otra solución sería rellenar los vectores con un mínimo de 1 elemento en el índice 0, así UBound() no te devuelve error. También puedes declarar un registro con el vector y una variable que lleve la cuenta del número de elementos:

Código: Text
  1.  
  2. public type tArreglo
  3.      Arreglo() as Tipo1
  4.      NElementos as Integer
  5. end type
  6.  
  7.  

Cada vez que pongas un elemento en Arreglo, sumas uno a NElementos.

Salud y república

Nebire

  • Miembro HIPER activo
  • ****
  • Mensajes: 670
    • Ver Perfil
Re: Funcion para Saber si Un Arreglo Esta Vacio
« Respuesta #4 en: Domingo 31 de Agosto de 2008, 20:46 »
0
Cita de: "m0skit0"
Cita de: "cpmario"
Debes basarte en la otra variable (la que suma) la i


Código: Text
  1.  
  2. public type tArreglo
  3.      Arreglo() as Tipo1
  4.      NElementos as Integer
  5. end type
  6.  
  7.  

Cada vez que pongas un elemento en Arreglo, sumas uno a NElementos.

Salud y república

Esto es una tontería la función Ubound() es perfecta y lo es por si misma, tampoco hace falta otro contador posterior sino en todo caso anterior que a la vez sirve para la verificación...

Código: Text
  1.  
  2.   dim limite as integer
  3.    
  4.    limite= ubound(Arreglo)
  5.    if limite <>-1 then
  6.         '  la matriz está dimensionada, tiene elementos...
  7.         redim preserve Arreglo(limite +1)
  8.   else
  9.      ' la matriz no está dimensionada
  10.   end if
  11.  
  12.  
  13.  
«Ma non troppo»
----> ModoVacaciones = False<----

m0skit0

  • Miembro de PLATA
  • *****
  • Mensajes: 2337
  • Nacionalidad: ma
    • Ver Perfil
    • http://fr33kk0mpu73r.blogspot.com/
Re: Funcion para Saber si Un Arreglo Esta Vacio
« Respuesta #5 en: Lunes 1 de Septiembre de 2008, 10:06 »
0
Perdón, señor listo Nebire, UBound da error si el array no tiene ningún elemento. Prueba esto:

Código: Visual Basic
  1.  
  2. Dim Lista() as Integer
  3. Dim a as Integer
  4.  
  5. a = UBound(Lista)
  6.  
  7.  

Nebire

  • Miembro HIPER activo
  • ****
  • Mensajes: 670
    • Ver Perfil
Re: Funcion para Saber si Un Arreglo Esta Vacio
« Respuesta #6 en: Lunes 1 de Septiembre de 2008, 18:07 »
0
Cita de: "m0skit0"
Perdón, señor listo Nebire, UBound da error si el array no tiene ningún elemento. Prueba esto:

Código: Visual Basic
  1.  
  2. Dim Lista() as Integer
  3. Dim a as Integer
  4.  
  5. a = UBound(Lista)
  6.  
  7.  

Gracias por lo de 'listo', no hacía falta, y perdonado estás... ignorar cosas es lo más normal, pero no deberías precipitarte sin investigar un poco al menos, no te parece...?. Crees que lógico hacer una afirmación sin conocer en profundidad lo que se hace y dice ?.

Prueba el siguiente código comentado... y fíjate que las 3 primmeras líneas de tu código son casi idénticas a las mías, la diferencia está en lo que ignoras

Código: Visual Basic
  1.  
  2. ' a nivel de módulo, en el formulario
  3.  
  4. Dim Lista    ' de entrada se define como una variant, no un array...
  5. Dim a as Integer
  6.  
  7.  
  8. Private Sub Form_Click()
  9.   'for k= 0 to 15
  10.  
  11.      If Not IsArray(Lista) Then
  12.         Lista = Array()
  13.      End If
  14.  
  15.     a = UBound(Lista)   ' al llegar aquí esto nunca da error, incluso cuando Lista() no ha sido inicializado todavía
  16.  
  17.      If UBound(Lista) = -1 Then
  18.         ' aquí se entrará cuando el array no haya sido inicializado, incluso cuando es nothing, para probar esto activar el bucle for o pulsar más de 10 veces en el formulario...
  19.         msgbox "El array no ha sidfo inicializado, pero no da error...."
  20.         ReDim Lista(0 To 0)    ' por ejemplo se aprovecha para inicializar el array a 1 elemento... o lo que se quiera
  21.    Else
  22.         ReDim Preserve Lista(UBound(Lista) + 1)  ' se redimensiona en un elemento más que es lo que quería el que abrió el hilo    
  23.    End If
  24.     msgbox "La matriz LISTA tiene " & a  & " elementos.... palabra de ley."
  25.  
  26.        'eliminar la matriz
  27.       if ubound(lista)=10 then
  28.           set Lista=nothing
  29.       end if
  30.  
  31.   ' next
  32. end sub
  33.  
  34.  
  35.  

Ahora pruébalo paso a paso y me comentas.... para la próxima si no encuentras la solución, simplemente dí 'No lo veo', queda más propio con la verdad decir no lo veo que decir es falso, cuando es verdadero...
«Ma non troppo»
----> ModoVacaciones = False<----

m0skit0

  • Miembro de PLATA
  • *****
  • Mensajes: 2337
  • Nacionalidad: ma
    • Ver Perfil
    • http://fr33kk0mpu73r.blogspot.com/
Re: Funcion para Saber si Un Arreglo Esta Vacio
« Respuesta #7 en: Martes 2 de Septiembre de 2008, 08:33 »
0
Primero, disculpa lo de "listo". No iba con mala intención, aunque lo de "tontería" por tu parte supongo que tampoco.  &lt;_&lt;

Segundo, en este tema he investigado más de lo que te imaginas puesto que es un asunto del trabajo.

Declarar variables variant es de mala programacion puesto que son lentas y ocupan memoria innecesariamente. Yo prefiero mi solución porque es más rápida a la hora de ejecutar y ocupa menos memoria. Como regla general, JAMÁS deben usar variables de tipo Variant.

Nebire

  • Miembro HIPER activo
  • ****
  • Mensajes: 670
    • Ver Perfil
Re: Funcion para Saber si Un Arreglo Esta Vacio
« Respuesta #8 en: Martes 2 de Septiembre de 2008, 11:39 »
0
Cita de: "m0skit0"
Declarar variables variant es de mala programacion puesto que son lentas y ocupan memoria innecesariamente. Yo prefiero mi solución porque es más rápida a la hora de ejecutar y ocupa menos memoria. Como regla general, JAMÁS deben usar variables de tipo Variant.
Efectivamente como regla general, no para todo caso habido o por haber... esta es una digna excepción.
En cuanto a que tu solución es más rápida y ocupa menos no estoy de acuerdo... tu fabricas un registro por el sólo hecho de no tener claro como mediar con un array no inicializado. si montas la solución que te doy en una función del modo que más te convenga (obtener true, false para ver si está declarado o devolviendo un entero indicando su límite a sabiendas de que -1 indica no inicializado) creo que es más rápido y agota menos memoria por la sencilla razón de que si finalmente tu programa hubiera de tener pongamos 300 arrays tu solución crearía 300 variables extras para reconocer su tamaño, aparte 300 descriptores del registro que también ocupa lo suyo. Mi solución no tiene ese problema la función puede recibir cualquier array si lo pones como parámetro, es por tanto una función universal sean cuantas sean los arrays que tengas. Además puedes usar la misma función con parámetros adicionales opcionales para redimensionarlo...

Además un problema que suele tener la gente es que una vez que termina de usar un array no lo destruye, porque luego le 'cuesta' volver a construirlo más tarde si lo necesita, mi solución permite además dejar de temer ese caso, con lo que cuando se precise puede eliminarse el array sin contemplaciones y sin tener que hacer un código o vairables extra de comprobación y/io mantenimiento. También he visto gente que usa un registro y en él un buleano para señalar cuando destruye el array y no debe utilizarlo. Lo cual es más de lo mismo y que mi solución hace innecesario.

Piénsalo un poco, dale vueltas y exprimenta...

post data: adjunto Nota de Mocosoft
Código: Text
  1.  
  2.  
  3. Nota   Lasmatrices de cualquier tipo de datos requieren 20 bytes de memoria más cuatro bytes para cada dimensión de matriz, más el número de bytes que ocupan los propios datos. Puede calcular la memoria que ocupan los datos multiplicando el número de elementos de datos por el tamaño de cada elemento. Por ejemplo, los datos de una matriz unidimensional que consten de cuatro elementos de datos tipo Integer de dos bytes cada uno, ocupan ocho bytes. Los ocho bytes que requieren los datos más los 24 bytes necesarios para la matriz suman un requisito total de memoria de 32 bytes para dicha matriz.
  4.  
  5. Un tipo Variant que contiene una matiz requiere 12 bytes más que la matriz por sí sola.
  6.  
  7.  
Resumiendo si tienes 300 arrays en un programa y usas una función como indico sólo usarás 12 bytes más usando los 300 arrays usando un registro con un integer aparte del array usarás 2bytes por cada array dicho sea 600 bytes + el tamaño de los 300 descriptores de cada registro, el tiempo empleado en acceder a un registro siempre requiere calcular la dirección del registro + la de la variable, por lo que usar un registro siempre tendrá un tiempo de acceso mayor para calcular la dirección efectiva, y esto se aplica no sólo a la variable que lleva el contador del tamaño del array sino también para el propio array cada vez que se usa.
«Ma non troppo»
----> ModoVacaciones = False<----

m0skit0

  • Miembro de PLATA
  • *****
  • Mensajes: 2337
  • Nacionalidad: ma
    • Ver Perfil
    • http://fr33kk0mpu73r.blogspot.com/
Re: Funcion para Saber si Un Arreglo Esta Vacio
« Respuesta #9 en: Martes 2 de Septiembre de 2008, 12:05 »
0
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 (puesto que hay que consultar el campo VarType cada vez que se opera con ella y convertir el dato adecuadamente, vamos que es una llamada a una función cada vez que la usas) y la que más memoria ocupa (¡16! bytes siempre) (más que un String de VB que ya es decir), por lo tanto tu código va a ser más lento que mi ejemplo y va a ocupar más memoria.

Aparte, con la declaración de un registro uno se ahorra la llamada a UBound() que añade más lentitud aún. Y no hablemos de Array(). El programa en el que estoy trabajando ahora tiene por lo menos 50 arrays diferentes con más de 30000 (!) elementos cada uno. He probado varias formas (incluídos los Variants) para obtener el mejor rendimiento, y la que tú propones te puedo asegurar, sin ofender, que es la más lenta de todas. Pero en lo que estoy de acuerdo es que la tuya en es la forma más legible y comprensible, aunque eso a veces no sea suficiente.

Aqui te dejo un enlace al tipo Variant y las excepciones para usarlo. Un saludo.

En cuanto a tu P.D., te comento:

1. Uso el tamaño del array + el tamaño de la variable de control, generalmente Integer, es decir 2 bytes, por lo tanto, me ahorro 10 bytes por cada array que si usara Variant (sin contar los bytes extra del tipo Variant, claro)

2. Para acceder a los registros no se suma por software, se usa direccionamiento indexado, la suma es interna por CPU por tanto más rapida. De todas formas puedes prescindir del registro y crear una varible independiente, aunque es más cutre y la diferencia no merece la pena.

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á.
« última modificación: Martes 2 de Septiembre de 2008, 14:00 por m0skit0 »

m0skit0

  • Miembro de PLATA
  • *****
  • Mensajes: 2337
  • Nacionalidad: ma
    • Ver Perfil
    • http://fr33kk0mpu73r.blogspot.com/
Re: Funcion para Saber si Un Arreglo Esta Vacio
« Respuesta #10 en: Martes 2 de Septiembre de 2008, 12:48 »
0
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
  1.  
  2. Private Sub Funcion1()
  3.     Dim Lista As Variant
  4.     Dim a As Integer
  5.     Dim i As Long
  6.    
  7.     If Not IsArray(Lista) Then
  8.         Lista = Array()
  9.     End If
  10.    
  11.     a = UBound(Lista)
  12.     ReDim Preserve Lista(a + 1)
  13.    
  14.     For i = 1 To 100000
  15.         ReDim Preserve Lista(UBound(Lista) + 1)
  16.         Lista(i) = 1
  17.     Next i
  18. End Sub
  19.  
  20.  

Código: Visual Basic
  1.  
  2. Private Sub Funcion2()
  3.     Dim Lista As tTipo
  4.     Dim a As Integer
  5.     Dim i As Long
  6.    
  7.     Lista.NElementos = 0
  8.    
  9.     a = Lista.NElementos
  10.     ReDim Preserve Lista.Lista(a + 1)
  11.    
  12.     For i = 1 To 100000
  13.         Lista.NElementos = Lista.NElementos + 1
  14.         ReDim Preserve Lista.Lista(Lista.NElementos)
  15.         Lista.Lista(i) = 1
  16.     Next i
  17. End Sub
  18.  
  19.  

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]
El mensaje contiene 1 archivo adjunto. Debes ingresar o registrarte para poder verlo y descargarlo.

m0skit0

  • Miembro de PLATA
  • *****
  • Mensajes: 2337
  • Nacionalidad: ma
    • Ver Perfil
    • http://fr33kk0mpu73r.blogspot.com/
Re: Funcion para Saber si Un Arreglo Esta Vacio
« Respuesta #11 en: Martes 2 de Septiembre de 2008, 12:59 »
0
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.

Nebire

  • Miembro HIPER activo
  • ****
  • Mensajes: 670
    • Ver Perfil
Re: Funcion para Saber si Un Arreglo Esta Vacio
« Respuesta #12 en: Jueves 4 de Septiembre de 2008, 16:29 »
0
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á.

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.
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
  1.  
  2. Tiempo 'On error' : 0'466875    Memoria en bytes: 60.000
  3. Tiempo 'Registro' : 0'375         Memoria en bytes: 180.000
  4. Tiempo 'Variant' : 1'17175       Memoria en bytes: 60.000
  5.  

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
  1.  
  2.  
  3. ' este proyecto presenta una comparativa con 3 métodos diferentes para
  4. '   verificar si un array está INICIALIZADO (O NO), y proceder en cada caso
  5. '   a redimensionarlo o iniciarlo.
  6.  
  7.  
  8.  ' metodo 2 emplea este registro
  9.  Private Type miRegistro
  10.     suArray() As Integer
  11.     contador As Integer
  12.  End Type
  13.  
  14.  Dim suArray() As Integer   ' emplean métodos 0 y 1  método ON ERROR
  15.  Dim miArray                ' lo emplea método 1            método VARIANT
  16.  Dim tuArray As miRegistro  ' emplea el método 2    método REGISTRO
  17.  
  18.  
  19.  ' 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
  20. '   hscrRep es un scroll horizontal para modificar el número de repeticiones, finalmente hay un label que indica el valor del scroll...
  21.  
  22. Private Sub ComCalcular_Click()
  23.     Dim t As Single     ' para el cálculo del tiempo empleado
  24.     Dim tamByte As Long ' para el cálculo de la memoria que ocupa
  25.    
  26.     Me.TxtTiempo.Text = 0
  27.     Me.TxtByte.Text = 0
  28.     DoEvents
  29.     If FraMetodo.Tag = 0 Then                                      ' Método ON ERROR
  30.         t = Timer
  31.         For j = 0 To 10
  32.             For k = 1 To HScrRep.Value
  33.                 If limiteA(suArray) <> -1 Then
  34.                     ReDim Preserve suArray(0 To UBound(suArray))
  35.                     suArray(UBound(suArray)) = k
  36.                 Else
  37.                     ReDim suArray(0 To 0)
  38.                     suArray(0) = 0
  39.                 End If
  40.             Next
  41.             Erase suArray
  42.         Next j
  43.         TxtTiempo.Text = Timer - t
  44.         TxtByte.Text = (tamByte + HScrRep.Value) * Len(suArray(0))
  45.     ElseIf FraMetodo.Tag = 1 Then                        ' Método VARIANT
  46.         t = Timer
  47.         For j = 0 To 10
  48.             For k = 1 To HScrRep.Value
  49.                 'MsgBox VarType(miArray)
  50.                 If limiteB(miArray) <> -1 Then
  51.                     ReDim Preserve suArray(0 To UBound(suArray))
  52.                     suArray(UBound(suArray)) = k
  53.                 Else
  54.                     ReDim suArray(0 To 0)
  55.                     suArray(0) = 0
  56.                 End If
  57.                 miArray = suArray
  58.             Next
  59.             Erase suArray
  60.             Set miArray = Nothing
  61.         Next j
  62.         TxtTiempo.Text = Timer - t
  63.         TxtByte.Text = (tamByte + HScrRep.Value) * Len(suArray(0))
  64.     Else                                                                        ' Método REGISTRO
  65.         t = Timer
  66.         For j = 0 To 10
  67.             tuArray.contador = -1
  68.             For k = 1 To HScrRep.Value
  69.                 If tuArray.contador <> -1 Then
  70.                     tuArray.contador = tuArray.contador + 1
  71.                     ReDim Preserve tuArray.suArray(0 To tuArray.contador)
  72.                 Else
  73.                     tuArray.contador = 0
  74.                     ReDim tuArray.suArray(0 To 0)
  75.                 End If
  76.                 tuArray.suArray(tuArray.contador) = k
  77.             Next
  78.             Erase tuArray.suArray
  79.         Next
  80.         TxtTiempo.Text = Timer - t
  81.         TxtByte.Text = (tamByte + HScrRep.Value) * Len(tuArray)
  82.     End If
  83.    
  84.     Erase suArray, tuArray.suArray
  85. End Sub
  86.  
  87. ' sólo procesa el tipo integer, para otro tipo debe proveerse otra función casi idéntica
  88. Public Function limiteA(matriz() As Integer) As Integer
  89.     On Local Error GoTo limiteError
  90.    
  91.     limiteA = UBound(matriz)
  92.     Exit Function
  93.    
  94. limiteError:
  95.     limiteA = -1
  96. End Function
  97.  
  98. ' procesa tanto matrices de enteros como de cadenas, bytes, long etc....
  99. Public Function limiteB(matriz As Variant) As Integer
  100.     If Not IsArray(matriz) Then
  101.         matriz = Array()
  102.     End If
  103.    
  104.     limiteB = UBound(matriz)
  105. End Function
  106.  
  107.  
  108. Private Sub Form_Load()
  109.     FraMetodo.Tag = 0
  110. End Sub
  111.  
  112. Private Sub HScrRep_Change()
  113.     Me.LabRep.Caption = "Repeticiones: " & HScrRep.Value
  114. End Sub
  115.  
  116. Private Sub OptMetodo_Click(Index As Integer)
  117.     FraMetodo.Tag = Index
  118. End Sub
  119.  
  120.  

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...
El mensaje contiene 1 archivo adjunto. Debes ingresar o registrarte para poder verlo y descargarlo.
«Ma non troppo»
----> ModoVacaciones = False<----

Jimbenit

  • Miembro MUY activo
  • ***
  • Mensajes: 269
  • Nacionalidad: co
    • Ver Perfil
    • http://ingenieriacivil.foroactivo.com
Re: Funcion para Saber si Un Arreglo Esta Vacio
« Respuesta #13 en: Miércoles 10 de Septiembre de 2008, 20:25 »
0
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
  1. Private Sub Form_Load()
  2.     Dim Nilson As String
  3.     MsgBox ("Saludos"), , "Nilson Yair"
  4. End Sub
  5.  
  6.  


Yo quiero mucho a Toph ---> Mi Web]http://ingenieriacivil.foroactivo.com[/url]

Astronald

  • Nuevo Miembro
  • *
  • Mensajes: 4
    • Ver Perfil
Re: Funcion para Saber si Un Arreglo Esta Vacio
« Respuesta #14 en: Martes 7 de Octubre de 2008, 01:36 »
0
No se....., no encontre en internet entonces hice esta funcion

Código: Text
  1.  
  2. Private Function LimiteArray(ByRef Arreglo As Variant) As Long
  3.     On Error GoTo SinIniciar
  4.         LimiteArray = UBound(Arreglo)
  5.     Exit Function
  6. SinIniciar:
  7.     LimiteArray = -1
  8. End Function
  9.  
  10.  

lo otro es que si redimensionamos con esta funcion la primera es igual a cero
ejemplo,
Código: Text
  1.  
  2. redim Arreglo(limiteAray(arreglo)+1)
  3.  
  4.  
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
« última modificación: Miércoles 8 de Octubre de 2008, 16:11 por Astronald »

Jimbenit

  • Miembro MUY activo
  • ***
  • Mensajes: 269
  • Nacionalidad: co
    • Ver Perfil
    • http://ingenieriacivil.foroactivo.com
Re: Funcion para Saber si Un Arreglo Esta Vacio
« Respuesta #15 en: Miércoles 8 de Octubre de 2008, 00:17 »
0
B) Bienvenido amigo...


Yo quiero mucho a Toph ---> Mi Web]http://ingenieriacivil.foroactivo.com[/url]

Nebire

  • Miembro HIPER activo
  • ****
  • Mensajes: 670
    • Ver Perfil
Re: Funcion para Saber si Un Arreglo Esta Vacio
« Respuesta #16 en: Miércoles 8 de Octubre de 2008, 08:26 »
0
Cita de: "Astronald"
No se....., no encontre en internet entonces hice esta funcion
 las variables Variat  para crear arreglos en esta utilizo una pero solo por referencia para permitir todo tipo de matrices

Es como decir que no te gustan las ruedas pero que las utilizas sólo para girar... Para qué otra cosa puede utilizarse algo sino para aquello para lo que fue diseñado ????, la función de un Variant es precisamente esa, la de poder utilizarse con limitaciones que tiene otros tipos de datos, para poder hacerlo así ella misma tiene que ser un tipo de datos. Usar una vaiant con otros propósitos es como usar una rueda cuadrada para hacer una bicicleta. Cada cosa tiene sus propios datos más aptos para lo que se pretende usar, por ejemplo para definir colores usamos un long o una matriz de bytes que es equivalente a un long, nadie va a usar una cadena de strings, tipológicamente un carácter puede alojar un byte pero el tratamiento de cadenas sólo encuentra su sentido en el lenguaje humano, no en las matemáticas, las definiciones de colores y sus operaciones y aplicaciones son puramente matemáticas, las aplicaciones y operaciones de strings son relativamente lentas comparadas con operaciones maemáticas, por tanto usar un tipode datos fuera del espacio para lo que tiene su diseño, no es que sea un error es que simplemente habla del escaso conocimiento que un usuario pueda tener sobre un tipo de datos.

Un ejemplo de la vida misma...
Quien mejor que un médico para atender en un hospital, que es el 'tipo de datos' requerido para el caso, y que mejor que el tipo de datos 'cocinero' para la clase restaurante y ni un médico ni un cocinero usaríamos como guardaespaldas de un mafioso porque cada uno tiene su área de aplicación. Eso no quita que haya un 'tipo de datos' que siendo médico no es muy buen médico y que siendo cocinero no es muy buen cocinero y que siendo guardaespaldas tampoco sea un buen guardaespaldas, ahora bien cuando usaríamos a este tipo?... queda claro que no en cualquier situación pero si que es patente su utilidad preferible a cada uno de los otros en determinadas situaciones, por ejemplo en una zona de guerra, cada destacamento de pocos hombres no pueda contar con umn médico o un cocinero, posiblemente todos sean expertos guerrilleros entonces el tipo de datos que tanto es coninero  como médico como guerrillero aunque no rinda en ninguna de las áreas como el tipo de datos dedicado tiene más utilidad que  carecer de ello.
 
Lo mismo sucede en programación, los tipos de datos tienen su especialización y el variant fue concebido para usarse en las zonas límites entre tipos de datos como por ejemplo muchas llamadas a las API quien lo usa para sustituir a un tipo de datos genérico simplemente no es consciente de que es un Variant, ni conoce la utilidad de los tipos de datos.

La conversación trataba sobre como ha resuelto cada uno ese tema en cuestión, los métodos que yo expuse son los métodos que yo usaba al principio, cuando al caso, era muy frecuente el uso para dicha función, si sólo se iba a usar pocas veces (tal vez 2 o 3) en un programa uno lo suele resolver con el 'on error...' como ya lo expuso nuestro amigo amigo cpMario casi al inicio del post. Para un uso intensivo de dicha función yo utilizo realmente un API que hay para esta cuestión.

Un Variant tiene su sitio en la programación, quizás el errror de MS fuera no explicarse bien. Ellos lo definieron como un tipo de datos 'especial' pero que puede usarse como un tipo de datos 'normal', y con ello lo que querían decir  era que no había que hacer cosas 'raras' para usarlo sino usarlo del mismo modo que el resto de tipos (pero no para hacer lo mismo que el resto de tipos para eso se definió como especial). Cuando declaramos un objeto y o asignamos un dato al mismo el procedimiento es distinto de los tipos de datos genéricos es sólo esto lo que se quería entender como 'normal', su declaración y asignaciones, es decir su tratamiento pero no su utilidad. Los que no habíais nacido o erais muy pequeños e ignorabais siquiera lo que era la programación cuando apareció Visual Basic es normal que no conozcais detalles que se van perdiendo y olvidando con el tiempo y especialmente cuando desde la enseñanza siempre le han dedicado un 'mal de ojo' al Basic en general.
«Ma non troppo»
----> ModoVacaciones = False<----

Astronald

  • Nuevo Miembro
  • *
  • Mensajes: 4
    • Ver Perfil
Re: Funcion para Saber si Un Arreglo Esta Vacio
« Respuesta #17 en: Miércoles 8 de Octubre de 2008, 14:55 »
0
Sin querer entrar en conflictos te muestro este apartado que esta en la MSDN si quieren comprobarlo por favor busquen optimizar codigo.

Y lo otro es que creo mas costoso que los desarrollador nos pongamos a discutir...

Optimizar Codigo (Fuene MSDN)

A menos que desarrolle tareas como la generación de fractales, sus aplicaciones raramente se verán limitadas por la velocidad de ejecución del código. Normalmente son otros factores, como la velocidad de vídeo, los retrasos de la red o la actividad del disco, los que limitan las aplicaciones. Por ejemplo, cuando un formulario tarda en cargarse, puede deberse al número de controles y gráficos del formulario más que a la lentitud del código del evento Form_Load. Sin embargo, puede encontrar puntos del programa en los que la velocidad del código es el factor principal, especialmente en las rutinas a las que se llama con mucha frecuencia. Cuando éste sea el caso, puede usar varias técnicas para incrementar la velocidad real de las aplicaciones:

Evitar el uso de variables Variant.
Usar variables Long Integer y aritmética de números enteros.
Pasar a variables las propiedades utilizadas con mayor frecuencia.
Usar variables de nivel de módulo en lugar de variables estáticas.
Reemplazar las llamadas a procedimientos por código en línea.
Usar constantes siempre que sea posible.
Pasar argumentos con ByVal en lugar de ByRef.
Usar argumentos opcionales con tipo.
Usar colecciones.
Incluso si no va a optimizar la velocidad del código, conviene tener presentes estas técnicas y los principios en los que se basan. Si adquiere el hábito de elegir algoritmos más eficientes al escribir código, obtendrá una ventaja adicional a la velocidad de la aplicación.

Evitar el uso de variables Variant
El tipo de datos predeterminado de Visual Basic es Variant. Es cómodo para los programadores principiantes y en aplicaciones en las que la velocidad de procesamiento no es importante. Sin embargo, si piensa optimizar la velocidad real de su aplicación, debe evitar el uso de variables Variant. Como Visual Basic convierte las variables Variant al tipo de datos apropiado en tiempo de ejecución, las operaciones con otros tipos de datos simples eliminan este paso adicional y son más rápidas que sus equivalentes Variant.

Un buen sistema para no usar variables Variant es usar la instrucción Option Explicit, que le obliga a declarar todas las variables. Para usar Option Explicit, active la casilla de verificación Requerir declaración de variables en la ficha Editor del cuadro de diálogo Opciones, disponible en el menú Herramientas.

Tenga cuidado cuando declara múltiples variables: si no utiliza la cláusula As tipo, se considerarán variables Variant. Por ejemplo, en la siguiente declaración, X e Y son Variant:

Dim X, Y, Z As Long

Escritas de esta manera, las tres variables son de tipo Long:

Dim X As Long, Y As Long, Z As Long

Para obtener más información   Para aprender más acerca de los tipos de datos de Visual Basic, vea "Tipos de datos" en "Fundamentos de programación".

Astronald

  • Nuevo Miembro
  • *
  • Mensajes: 4
    • Ver Perfil
Re: Funcion para Saber si Un Arreglo Esta Vacio
« Respuesta #18 en: Miércoles 8 de Octubre de 2008, 16:30 »
0
agregue la funcion a el modulo donde se hacia la prueba de tiempo de duración y es la opcion mas lenta..

Funcion 1: 971
Funcion 2: 62
Funcion 3: 13617

que tristeza entonces hice esta otra

Código: Text
  1.  
  2. Private Sub Funcion3()
  3.     Dim Lista() As Integer
  4.     Dim a As Integer
  5.     Dim i As Long
  6.     For i = 0 To 100000
  7.         AgregarElemento Lista
  8.         Lista(i) = 1
  9.     Next i
  10. End Sub
  11.  
  12. Private Sub AgregarElemento(ByRef Arreglo As Variant)
  13.     On Error GoTo SinIniciar
  14.     ReDim Preserve Arreglo(UBound(Arreglo) + 1)
  15. Exit Sub
  16. SinIniciar:
  17.     ReDim Arreglo(0)
  18. End Sub
  19.  
  20.  

y o sorpresa ....

Funcion 1: 959
Funcion 2: 59
Funcion 3: 76

Bueno no es la mas rapida pero...
 * No tenemos que actualizar la variable NElementos, lei y el hecho de utilizar un procedimiento hace que se se mas costoso el codigo, pero sino lo utilizamos se perderia la modularidad y entonces tendriamos que repetir la misma linea en todos los segmentos donde lo utilizamos.

Otra cosa es que la funcion Ubound cuesta, y en la funcion 2 no se utiliza...
y bueno tambien falta ver que necesitamos hacer consultar el arreglo, o agregar un elemento.

Nebire

  • Miembro HIPER activo
  • ****
  • Mensajes: 670
    • Ver Perfil
Re: Funcion para Saber si Un Arreglo Esta Vacio
« Respuesta #19 en: Jueves 9 de Octubre de 2008, 01:36 »
0
A lo largo de la conversación ya se ha debatido acerca de los Variant, no resulta necesario darle más vueltas. Si has leído el post entero verás que no hace falta añadir nada más. Los variant deben usarse para casos especiales donde su uso tenga significado, si no es así se está desaprovechando capacidades de proceso.

En cuanto a los tiempos de cálculo, te señalo nuevamente que lo más rápido es usar la API si se va a hacer un uso intensivo preguntando si un array está declarado, si no se va a hacer un uso intensivo prácticamente da igual el método que se use, ya que sólo es significativo cuando se va a hacer varios millones de consultas para 4 ó 5 consultas en un minuto -no  i m p o r t a- . si has leído el post verás que 300.000 ejecuciones de un bucle en el peor caso de los 3 que presenté más arriba tardaba poco más de 1sg. por tanto no merece la pena ni discutirlo.

De todos modos si quieres el más rápido te doy un código para que lo pruebes... y dejemos esta conversación ya, no hay nada más que añadir, a lo sumo si a alguien le cuesta entender algo, y end icho caso que pregunte...

Este código será el doble o el triple (al menos) de rápido que cualquier otro que hayas usado en VB

Colcar un boton y un textbox en el formulario.
Código: Visual Basic
  1.  
  2. Private Declare Sub ArrayDeclarado Lib "msvbvm60.dll" Alias "GetMem4" (elArray() As Any, devol As Long)
  3.  
  4. Private Sub Command1_Click()
  5.         dim n as long, t as single, tamaño as long
  6.         dim apiArray() as integer
  7.  
  8.         t = Timer
  9.         For j = 0 To 10
  10.            for k= 0 to 30000
  11.                 Call ArrayDeclarado(apiArray, n)
  12.                 If n > 0 Then
  13.                     ReDim Preserve apiArray(0 To UBound(apiArray))
  14.                     apiArray(UBound(apiArray)) = k
  15.                 Else
  16.                     ReDim apiArray(0 To 0)
  17.                     apiArray(0) = 0
  18.                 End If
  19.             Next
  20.             Erase apiArray
  21.         Next j
  22.        Text1.Text = Timer - t
  23.        Tamaño = 300000 * Len(apiArray(0))
  24.         msgbox "Tardó: " & Text1.Text  & "sg.  y el tamaño de la matriz era: " & Tamaño
  25. end sub
  26. ' NOTA: el código se ha embutido de las mismas características que se dieron algunos mensajes más arriba para compararlo en idénticas condiciones.
  27.  
  28.  
p. d.: fíjate en la declaración de la API como se declara el parámetro 'elArray' como as 'any' (cualquier tipo) precisamente para relajar la comprobación de tipos... si no fuera así, esa función requeriría una copia específica por cada tipo de datos y sucedería igual con muchísimas funciones...
«Ma non troppo»
----> ModoVacaciones = False<----