Eliminar filas con una condición excel vba
[*****Dante buenos días
Una consulta como eliminar filas si no tiene notas desaprobadas por ejemplo en sus respectivas celdas tengo esto.
Carlos 15 /18/ 13 / 16/ 15/ 19/ 12 ------------------------>Fila a eliminar
Hunter 16 / 15 /08/ 16/ 19/ 18 / 10 ----------------> no elminar
Hunter 16 / 15 /11/ 16/ 19/ 18 / 10 ----------------> no elminar
intenté con esto
Sub borrarcell() Set r = Range("D7:O71") ' For Each c In r.Rows If c > 10 Then ' Rows(c).EntireRow.Delete End If Next c End Sub
2 Respuestas
No entendí que son "notas desaprobadas".
Según tu ejemplo, si en alguna de las celdas de cada fila tiene un número menor o igual a 10 entonces esa fila no se elimina, de lo contrario, es decir, si todos los números son mayores a 10, entonces esa fila se elimina.
Si es correcto, entonces la macro sería así:
Sub borrarcell() 'Por.Dante Amor Set rango = Range("D7:O71") f_ini = rango.Cells(1, 1).Row f_fin = rango.Rows.Count + f_ini - 1 c_ini = rango.Cells(1, 1).Column c_fin = rango.Columns.Count + c_ini - 1 For i = f_fin To f_ini Step -1 existe = False For j = c_ini To c_fin If Cells(i, j) <= 10 Then existe = True Exit For End If Next If existe = False Then Rows(i).Delete End If Next End Sub
Nota: Recuerda que cuando borras filas, debes hacerlo de abajo hacia arriba, de lo contrario deberás controlar el contador, ya que si borras la fila donde va tu contador se va a brincar una fila sin analizar. Para que te quede más claro, si vas en la fila 11 y eliminas la fila 11, entonces la fila 12 ahora es la fila 11, pero tu contador en el siguiente ciclo pasa a 12, entonces en el siguiente ciclo revisa la fila 12, eso significa que ahora revisará la fila 13, porque la fila 11 fue eliminada, entonces tendrías que retroceder en 1 tu contador. Mejor realiza la validación de abajo hacia arriba y de esa forma no te preocupas por el contador del ciclo. Utilizando el contador tal y como debe hacerse, de manera lineal.
.
'S aludos. Dante Amor. Recuerda valorar la respuesta. G racias
.
Avísame cualquier duda
.
En una hoja nueva con los siguientes datos:
Prueba la siguiente macro:
Sub borrarcell3() Dim r As Range, c As Range Set r = Range("D7:D12") For Each c In r If c.Value > 10 Then c.EntireRow.Delete End If Next End Sub
Lo que hace la macro es revisar el dato de las celdas D7 a D12, si el dato es mayor a 10 entonces elimina la fila.
En teoría la macro debería eliminar las filas 8, 10 y 11. Pero si ejecutas la macro, solamente elimina las filas 8 y 10. No borra la fila 11, porque el control está brincando a la siguiente fila (esto ya lo expliqué)
Es por eso que se debe llevar el control de la fila eliminada.
No hay que revisar celda por celda de cada fila, también se puede revisar el número menor de la fila, si el número menor de la fila es mayor a 10 entonces eliminamos la fila, quedaría así:
Sub EliminaFila() 'Por.Dante Amor Set rango = Range("D7:O12") f_ini = rango.Cells(1, 1).Row f_fin = rango.Rows.Count + f_ini - 1 c_ini = rango.Cells(1, 1).Column c_fin = rango.Columns.Count + c_ini - 1 For i = f_fin To f_ini Step -1 wmin = WorksheetFunction.Min(Range(Cells(i, c_ini), Cells(i, c_fin))) If wmin > 10 Then Rows(i).Delete Next End Sub
sal u dos
- Compartir respuesta
Manteniendo tu misma idea:
Sub borrarcell () Dim r As Range, c As Range Set r = Range("D7:O71") For Each c In r If c.Value > 10 Then c.EntireRow.Delete End If Next c End Sub
Comentas
Abraham Valencia
[Hola Abrahan buenas tardes.
La macro se ejecuta pero no cumple con esta descripción
'
"Si en alguna de las celdas de cada fila tiene un número menor o igual a 10 entonces esa fila no se elimina, de lo contrario, es decir, si todos los números son mayores a 10, entonces esa fila se elimina."
Disculpa por meter temas insulsos a tu post. A partir de este momento me abocaré a ver solo tu dilema, aunque sigo sospechando que es cuestión de formatos. Un abrazo.
Abraham Valencia
Ya vi tus datos, ahora sí puedo estar seguro de que te ayudaría y en realidad hay varias formas de hacerlo, con "For Next" como ya te propusieron, con otras instrucciones y también con "For Each" pero "jugando" con colecciones. Dado que no son "tantos" datos, en términos de velocidad casi te será imperceptible la diferencia entre cualquier forma pero, programáticamente hablando, siempre es más eficiente una instrucción que otra.
Yo hoy ando con tiempo, si deseas probamos algo usando For Each y "colecciones" ¿te parece? Quizá, a la vista, podría parecer medio enredado, pero sería lo más "rápido" y que use menos memoria.
Comentas
Abraham Valencia
Te paso mi ejemplo que aproximadamente trabajaré con 1000 datos
https://www.dropbox.com/s/i78f3ez9qu88lil/PRUEBA%20v2.xlsx?dl=0
Buenas tardes Abraham, es probable que trabaje aprox. con 1000 datos (consolidado de notas)
Probemos con este ejemplo
https://www.dropbox.com/s/i78f3ez9qu88lil/PRUEBA%20v2.xlsx?dl=0
Al final se me presentaron 1000 cosas pero bueno, así es la vida.
Vi tu segundo archivo y usando For-Each y colecciones, con casi 1000 registros se logra eliminar lo deseado en 17.07 segundos (4 GB RAM, 3 GHZ de velocidad). Otras opciones lo hacen en 17.4 y 18 segundos. Aquí una alternativa para que veas lo de las "colecciones":
https://1drv.ms/x/s!ApkTgtnWCTgAiAnPKlvO_CMe9p-0
Aunque para ser sincero yo creo que para disminuir el tipo lo idóneo sería una columna auxiliar con algo así:
=CONTAR.SI(D7:O7,"<=10")
Entonces en lugar de recorrer todas las celdas, solo se recorre esa columna auxiliar y las que tienes cero se borran. Eso disminuirá el tiempo en más de 90%
Comentas
Abraham Valencia
[Hola Abraham buenos días, de hecho que la macro es lenta, será por que los datos tienen que pasar por varios bucles, probaré con la segunda opción que indicas Gracias saludos.
Fuera de los bucles y las comparaciones, en general cuando a la propiedad "EntireRow" le aplicas el método "Delete", tiende a ser lento, por si acaso, y siendo en este caso cientos de filas, se entiende un poco al menos esa lentitud.
Examinando/tabajando solo la columna auxiliar, que recomiendo, se baja el tiempo a 13 segundos, pero como comento, es el "Delete".
Podría intentarse con algo como
Range("P3, P34, P45, P56").EntireRow.Delete
Y en lugar de los rangos se usa una variable con todos los rangos necesarios:
Range(variable).EntireRow.Delete
Pero el objeto Range tiene un límite de 255 caracteres en su argumento y los rangos a borrar suman... 3572 solo en este caso :(
Quizá dividiendo cada 255 caracteres y borrando en partes, pero, serían, en ese caso como 14 veces, no sé que tanto tiempo se ahorre con eso, aunque siempre sera mejor que borrar 300 veces (una por una). El dilema en ese caso es que es algo un poco "trabajoso".
Así vamos hasta el momento
Un abrazo
Abraham Valencia
- Compartir respuesta
Hola. La ventaja de usar "For Each" y objetos tipo rango, a diferencia de otro tipo de bucles, es que no es una obligación eso de que se borran filas de abajo hacia arriba, por si acaso. For-Each trabaja, para que se entienda mejor, con "colecciones" y, además de eso, es más rápido que un bucle "For-Next". Salu2 - Abraham Valencia
No es obligatorio, pero sí se debe revisar el control. Revisa la macro que puse para que observes que no está borrando todas las filas. Sin duda llevar el contador en memoria con un for each será más rápido, pero si no es eficiente de nada sirve... - Dante Amor
Claro, a eso iba, a que no es obligatorio y sé que tu macro no borra todas las filas, es más, la de Adriel, una vez corregida, tampoco borra todas y se aboca las que tienen los valores que él mencionaba, pero claro, en mi caso yo he tratado de respetar su forma de intentar plantear las cosas. Sobre la memoria y similares, así es, un bucle "For Each" es más rápido que un bucle "For Next", y más aún si se trabaja con dos "For Next" pero, también soy sincero y sé que con la cantidad de datos usados por Adriel, la verdad no se notará gran diferencia en el tiempo.Sobre eficiencia, en programación (bien hecha) sería algo así: Ambas formas pueden ser eficaces, pero For Each será más eficiente. - Abraham Valencia
Por eso no expliqué ni la macro de Adriel ni tu macro; solamente me avoqué a dar solución con una nueva macro que realmente funciona para la petición, que por cierto iba dirigida, desde un inicio, a "Dante". La segunda macro la puse solamente para que observen que la macro no está borrando todas las filas, la única macro que borra correctamente las filas es la primera macro que puse. - Dante Amor
Estimado, sugiero que veas lo siguiente:Has colocado, en tu ejemplo de supuesto error, lo siguiente:Set r = Range("D7:D12")Y lo correcto es, con tu mismo ejemplo:Set r = Range("D7:E12")¿Notas la diferencia? Prueba ahora y te darás cuenta. No es que una funcione "realmente" y la otra no como estás prácticamente afirmando al escribir "a única macro que borra correctamente las filas es la primera macro que puse, afirmación evidentemente errada. "For Each", como ya había adelantado, no funciona como "For Next".Sobre eso que dices de que el mensaje estaba, prácticamente, "solo" dirigido a ti, no olvides que es un foro público estimado. Un abrazo. - Abraham Valencia
Puntos gratis. De nada - Dante Amor
¿Puntos gratis? ¿Te refieres a ese sistema de puntuación de TodoExpertos? Siempre es gratis ¿cierto? pero la verdad es que eso es lo de menos, lo interesante es enseñar y divertirse, lo demás es superfluo desde mi punto de vista. Claro, si a ti te importan mucho esos puntos, y por eso tu frase "puntos gratis", cosa tuya estimado, tengo demasiados años en este mundo virtual como para, hoy en día, tomarle importancia a una cosa así. - Abraham Valencia
Como quieras. Pero también, deberías corregir tu macro para como bien dices "lo interesante es enseñar", de esa forma todos nos divirtamos; y no solamente criticar mi trabajo.Si quieres dar clases de For-each o For-Next, hazlo en tus respuestas, no sobre mi trabajo. - Dante Amor
Estimado Dante, tranquilo, tú eres el que se dio el trabajo de hacer capturas de pantalla y más cosas para intentar demostrar que estaba mal la macro que le corregí a Ariel jejeje, cosa que no era cierta. En mi caso, yo no tengo nada que corregir basado en la información, hasta el momento, alcanzada. Ya sobre nueva y/o más información se podría, de ser necesario, ajustar/corregir. Por cierto, no es mi intención criticar tu macro, ojo con eso, inicialmente comenté para aclarar lo de "abajo-arriba" que afirmaste y que después, ambos comentamos que no es un "principio", por decirlo de un modo. Tu macro, claro que funciona, nadie ha dicho lo contrario. - Abraham Valencia
Repito nuevamente, jamás dije que era obligatorio, por experiencia, el borrado es de abajo hacia arriba, sin embargo, también pueden hacerlo a la inversa, solamente tienen que tener cuidado en el control. Y lo de las imágenes es para explicar justamente la importancia de tener el control, de lo contrario no cumpliría el objetivo. Deberías leer con atención la petición del usuario, probar bebidamente cada macro y no solamente criticar mis respuestas. Porque desde luego es una critica, nada constructiva, pero al final critica. - Dante Amor
Estimado, yo lo dejo ahí pero en realidad, como sincera recomendación, el que debe de leer no soy yo, sino que si quieres mejorar tus ejemplos debes meterte más de lleno en la programación. Nos vemos. - Abraham Valencia
Mi macro funciona, tu macro no funciona. Sigue revisando y criticando mis respuestas para que aprendas un poco. No hay más que decir. - Dante Amor
Pensé que ers un diálogo de adultos, recién me percato de que no. Pensé que eras mayor de edad y/o una persona madura.Lee sobre como trabajan las "colecciones" y como trabajan los bucles netamente cíclicos (no lineales por si acaso). Con tu mismo (mal) ejemplo de capturas de pantalla ajusta el rango, como ya te había dicho y listo, funciona. Tú lo aplicaste mal porque evidentemente no conoces mucho del tema.Ah, con variables también de puede "autoajustar" dicho rango. Ahora sí te dejo, lee, verás que sumado a lo que haces como enviar datos a otras hojas, te hará un buen programador de VBA. - Abraham Valencia
Sin duda tengo derecho de replica, pero no para insultarte, como lo haces tú. No soy el mejor programador ni lo ando pregonando, estoy aprendiendo como muchos; y por supuesto que me falta mucho por aprender. Pero aquí la única macro que funciona es la mía, deberías preocuparte por arreglar tu macro. Deja de mirar la astilla de mi ojo y preocupate por la madera que tienes en tu ojo. - Dante Amor