Saltar al contenido

Ordenar un rango de celdas en memoria


Antoni

Recommended Posts

publicado

Hola:

Pues nada mas que lo que dice el título.

Ordena un rango de celdas en un array de rangos.

Saludos.

Public Celda() As Range 'Resultado de la función


Function MacroOrden(Rango As Range) As Integer
'
' -----------------------------------------------------
' Ordena un rango de una sola columna sin tocar la hoja
' Deja el resultado en el array de rangos: Celda
'
' Macro Antonio Junio de 2011
' ---------------------------
'
' Nota: Necesita una adaptación para Option Base 1
'
' -----------------------------------------------------
'
Application.ScreenUpdating = False

MacroOrden = 0 'Función correcta

'Controlamos que solo haya una columna en el rango
If Rango.Columns.Count > 1 Then
MacroOrden = 1 'Función errónea
Exit Function
End If

'Redimensionamos el array al nº de celdas + 1
ReDim Celda(Rango.Cells.Count)

'Cargamos el rango en el array
For Each c In Rango: Set Celda(x) = c: x = x + 1: Next

'Ordenamos el array
For x = 0 To UBound(Celda) - 1
For y = x + 1 To UBound(Celda) - 1
If Celda(y).Value < Celda(x).Value Then
Set Celda(UBound(Celda)) = Celda(x)
Set Celda(x) = Celda(y)
Set Celda(y) = Celda(UBound(Celda))
End If
Next
Next

'Redimensionamos el array al número de celdas
ReDim Preserve Celda(Rango.Cells.Count - 1)

'Exit Function

'Depuración
For x = 0 To UBound(Celda)
Debug.Print Celda(x).Address, Celda(x).Value
Next x

End Function[/CODE]

Saludos

publicado

Se ve interesante el código pero no le encuentro entrada, como se usa la función, favor poner un ejemplo.

esque algunos somos un poco lentos con codigos mas avanzados.

Salu2.xlsx

publicado

Buenas Master Macro

Muy útil para ordenar rangos de celda en casos en los que no queremos tocar las celdas para ganar en velocidad.

Veo que es una variación del método de ordenación sencillo por "Selección directa", el cual si lo miras, veras que tiene unas cuantas mejoras respecto al tuyo ya que realiza menor número de intercambios al usar una variable llamada Mínimo en la cual encuentra el numero más pequeño y solo al final del recorrido del bucle realiza el intercambio.

Te he modificado un pelín el código pero sigue haciendo exactamente lo mismo:

Puse un Else en el condicional para que se viera más clara la bifurcación del código sin Exit Function.

Redim Variable as Range, ya que si no, conviertes de nuevo el rango en un variant, redim re alberga pero no copia el tipo de dato, esto lo tienes que poner tu.

He definido y renombrado algunas variables, así como una variable auxiliar para el número de celdas (Solo para que se vea más claro)

Le he añadido una variable auxiliar para ahorrar el redim preserve.

Y el Screen Updating me imagino que era solo para depuraciones y solo tenias el primero.

Option Explicit
Public ArrCelda() As Range 'Resultado de la función


Function MacroOrden(Rango As Range) As Integer
'
' -----------------------------------------------------
' Ordena un rango de una sola columna sin tocar la hoja
' Deja el resultado en el array de rangos: Celda
'
' Macro Antonio Junio de 2011
' ---------------------------
'
' Nota: Necesita una adaptación para Option Base 1
'
' -----------------------------------------------------
'
Dim N As Long 'Numero de celdas en el array
Dim Aux As Range 'Rango auxiliar para la ordenacion y carga de array
Dim i As Long, j As Long 'Variables de control de bucle

N = Rango.Rows.Count
'Redimensionamos el array al nº de celdas
ReDim ArrCelda(0 To N - 1) As Range

MacroOrden = 0 'FuNión correcta

'Si hay mas de una columna
If Rango.Columns.Count > 1 Then
MacroOrden = 1 'FuNión errónea
'Si solo hay una columna
Else

'Cargamos el rango en el array
For Each Aux In Rango: Set ArrCelda(i) = Aux: i = i + 1: Next

'Ordenamos el array
For i = 0 To N - 1
For j = i + 1 To N - 1
If ArrCelda(j).Value < ArrCelda(i).Value Then
Set Aux = ArrCelda(i)
Set ArrCelda(i) = ArrCelda(j)
Set ArrCelda(j) = Aux
End If
Next
Next

'Depuración
For i = 0 To N - 1
Debug.Print ArrCelda(i).Address, ArrCelda(i).Value
Next i
End If
End Function[/CODE]

Una pregunta tengo, ¿qué es lo que hace exactamente Debug.Print Celda(x).Address, Celda(x).Value?, nunca había visto lo de Debug.Print.

Y ya para terminar y que te entretengas con los métodos de ordenación, te dejo una página con varios videos bastante curiosos que nos pusieron en clase el día que dimos los métodos de ordenación.

[b]Algoritmos de ordenación explicados mediante .... ¡bailes tradicionales![/b]

Se trata de ver visualmente como se ordenan los numericos por los métodos de ordenación mas importantes, (eso que hace tan mágicamente los ordenadores y que solo los programadores pueden imaginar pasando la traza :P), el tuyo es el cuarto video (Select-sort with gypsy folk dance) aun que con la mejora que te comenté.

Saludos amigo

publicado

Hola:

Para potter08:

Ejemplo para ordenar el rango A1:A10

En el Array Celdas te quedan las celdas ordenadas de menor a mayor o de mayor a menor en función de como recorras el Array. Equivale a la función JERARQUIA.

Retorno = MacroOrden range("A1:A10")
If Retorno = 1 Then
Msgbox "El rango solo puede contener una columna"
End If[/CODE]

[b][u]Para Santi:[/u][/b]

1) Me miro tus sugerencias y te cuento.

2) [b]Debug.Print[/b] equivale a MsgBox pero en la [b]ventana inmediato[/b] y sin detenerse

En el editor de VBA [b]Ver\Ventana Inmediato[/b] o Ctrl+G

Saludos

publicado

Hola:

Menos en la hora, estoy totalmente en desacuerdo con tu último mensaje.

Ahora en serio, salvo en esto:

Le he añadido una variable auxiliar para ahorrar el redim preserve.

Y el Screen Updating me imagino que era solo para depuraciones y solo tenias el primero.

De hecho el ScreenUpdating=False, no procede en la función ya que no realizamos ni selección ni cambio de celdas.

Y la variable auxiliar yo no la necesito porqué defino un elemento mas en el array y lo utilizo en su sustitución, luego esto, me obliga al Redim Preserve.

No comparto ninguna de tus afirmaciones, ya que el nº de iteraciones es siempre el mismo en tu código y en el mío. Puedes haberte equivocado de código al subirlo, ya que no le encuentro sentido a esto:

al usar una variable llamada Mínimo en la cual encuentra el numero más pequeño y solo al final del recorrido del bucle realiza el intercambio

En lo referente a Redim, he sacado este texto de la ayuda, y la interpreto exactamente al contrario de lo que me dices:

Puede utilizar la instrucción ReDim repetidamente para cambiar el número de elementos y dimensiones de una matriz. Sin embargo, no puede declarar una matriz de un tipo de datos y luego usar ReDim para cambiar la matriz a otro tipo de datos, a menos que la matriz esté contenida en una Variant. Si la matriz está contenida en una Variant, el tipo de los elementos se puede cambiar mediante una cláusula As tipo, a menos que esté utilizando la palabra clave Preserve, en cuyo caso no se permiten cambios al tipo de datos.

Es decir, solo las variables definidas como Variant se les podrá cambiar el tipo de datos con la instrucción Redim, en el resto de variables, no puede cambiarse el tipo de datos con esta instrucción.

Esta líneas pueden ser eliminadas:

'Exit Function

'Depuración
For x = 0 To UBound(Celda)
Debug.Print Celda(x).Address, Celda(x).Value
Next x[/CODE]

Estaban puestas solo para quien quisiera comprobar el resultado de la ordenación.

Muy bueno el video.

Besitos y me encanta que le dediques tiempo a mis aportes. Si el cielo existe, seguro que irás.

publicado

Antoni!!, me entendiste mal :mad:

Son dos temas distintos y releyendo entiendo tu confusion, supuse que ibas a buscar el metodo en vez de entender que yo te estaba exponiendo el codigo.

Tema1: Aqui te hablo del algoritmo "Seleccion directa",

Veo que es una variación del método de ordenación sencillo por "Selección directa", el cual si lo miras, veras que tiene unas cuantas mejoras respecto al tuyo ya que realiza menor número de intercambios al usar una variable llamada Mínimo en la cual encuentra el numero más pequeño y solo al final del recorrido del bucle realiza el intercambio.

Tema2: Aqui te hablo de las modificaciones a tu codigo y que nada tiene que ver con haber mejorado el algoritmo. Intente dejarlo claro con "hace exactamente lo mismo"

Te he modificado un pelín el código pero sigue haciendo exactamente lo mismo:

Ahora si que te paso un link directo para el algoritmo de seleccion directa, seguro que te resulta tremendamente familiar jejeje, hace exactamente lo mismo que el tuyo solo que ayudado de una variable auxiliar Minimo, deja el intercambio para el final del recorrido por lo que realiza menos intercambios y es mas rapido SELECCION DIRECTA

Selection-Sort-Animation.gif

El tema del redim, tienes razon en que dice eso y yo pensbaa exactamente igual, el tema es que si vas depurando el codigo, veras que sin el "as range", todas son variant, la verdad es que no se a que se puede deber o a saber que diablos estaria mirando cuando lo vi, pero te aseguro que lo vi, todas ponian variant :mad:

Si el cielo no es tan aburrido como me imagino, ojala Dios te escuche y haya sitio para todos los de aqui :rolleyes:

Saludos

publicado

Hola Santi:

Vale vale, "lo he pillao".

Lo miraré con detenimiento.

Saludos.

PD. Si el cielo no hace la vista gorda con la mayoría de los 7 pecados capitales, que no me llamen.

¡ Venga !, les dejo que mantengan la soberbia, la envidia y la avaricia, ¡ pero el resto me los pido !

Archivado

Este tema está ahora archivado y está cerrado a más respuestas.

×
×
  • Crear nuevo...

Información importante

Echa un vistazo a nuestra política de cookies para ayudarte a tener una mejor experiencia de navegación. Puedes ajustar aquí la configuración. Pulsa el botón Aceptar, si estás de acuerdo.