Etiqueta

11 febrero 2011

Uso del método $search


Uno de los temas más debatidos en Omnis Studio, es como moverse a través de una lista de modo eficaz. El “blog” de Bastiaan, recogía un artículo dedicado a esto que me ha parecido muy esclarecedor, por lo que me he decido a traducirlo al castellano y publicarlo en el blog de “Experiencias con Omnis Studio”.

Por lo que debemos empezar por dar las gracias a Bastiaan Olij y a Kelly Burgess por sus aportaciones.
Desde muy temprano Omnis nos ha provisto de funciones 4GL que nos permitían buscar y seleccionar líneas en una lista, pero en Omnis Studio, disponemos de un potente método denominado $search. Por supuesto podrá seguir usando los comandos 4GL tradicionales. Sin embargo enseguida notará que puede conseguir mejores resultados si hace uso del método $search. A continuación se muestran algunos ejemplos, pero antes debemos explicar que el método $search, consta de los siguientes 5 parámetros:

  1. El primero, es la búsqueda en sí misma, un cálculo que será avaluado para cada línea de la tabla objeto de búsqueda. Podrá usarse “$ref” como puntero hacia la línea que está siendo evaluada.
  2. El segundo parámetro, determinará si la búsqueda deberá realizarse desde el principio. Si es “kTrue” la búsqueda comenzará desde la línea 1. No obstante es importante hacer notar, que si la línea actual es “0”, la búsqueda siempre comenzará desde el principio.
  3. El tercero nos permitirá indicar si la búsqueda deberá afectar sólo a las líneas actualmente seleccionadas o por el contrario a toda la lista. Si es “kTrue” sólo las líneas actualmente seleccionadas serán evaluadas.
  4. El cuarto parámetro nos permitirá marcar las líneas encontradas como seleccionadas.
  5. Finalmente, un quinto parámetro nos permitirá, realizar el proceso inverso al descrito en el parámetro anterior, es decir nos permite marcar las líneas halladas como no seleccionadas.

Éste primer ejemplo, nos permite localizar la línea que cumple con los criterios de búsqueda especificados:

; Siempre será necesario hacer uso de los 5 parámetros
If lvMiLista.$search($ref.MiColumna = 'Buscame',ktrue,kfalse,kfalse,kfalse)>0
  ; La encontré
Else
  ; No existe
End If

 Selección de las líneas coincidentes con el criterio de búsqueda.

; Se usan los valores predeterminados para los parámetros
Do lvMiLista.$search($ref.MiColumna = 'Buscame')

Seleccionando todas las líneas.

Do lvMiLista.$search(kTrue)

Anulando la selección de todas las líneas.

; En este caso usamos un pequeño truco para anular la selección de sólo las líneas seleccionadas
Do lvMiLista.$search(kFalse,kTrue,kTrue)

Recorriendo las líneas seleccionadas.

; Aunque también es posible usar lvMiLista.$first(kTrue), poner $line a 0 nos ahorrará una línea de código
Calculate lvMiLista.$line as 0 ;; para comenzar desde el principio
While lvMiLista.$next(lvMiLista.$line,kTrue)
  ; Lo que quiera hacer
End While

Recorriendo las líneas coincidentes con el criterio de búsqueda, pero sin cambiar su estado actual.

Calculate lvMiLista.$line as 0 ;; para comenzar desde el principio
While          
lvMiLista.$search($ref.MiColumna='Buscame',kfalse,kfalse,kfalse,kfalse)>0
  ; Lo que quiera hacer
End While

Y, finalmente, un interesante procedimiento que le permitirá localizar las líneas en una lista, de modo mucho más rápido que usando un $search, pero con las siguientes dos limitaciones:

  1. La columna objeto de búsqueda deberá contener un valor único.
  2. La lista deberá estar ordenada por la columna objeto de búsqueda.

Evidentemente la necesidad de tener que ordenar la lista previamente, rebajará la ganancia de rendimiento, pero si ya se han recuperado los datos ordenados o si se deben realizar muchas búsquedas, tal sobrecarga no tendrá importancia alguna, el método expuesto a continuación forma parte de una clase “table”, pero también podría estar en una clase “object” o “code”, a la que pasar la lista a tratar como un parámetro:

tTableClass.$quickSearch(char pvNombreColumna, fieldref pvValor,
       int pvPrimeraLinea=1, int pvUltimaLinea=$cinst.$linecount)
--
;; Algoritmo de búsqueda basado en los conocidos “QuickSort” y “QuickSearch”
;; Recuerde que la lista debe estar ordenada y la columna debe contener valores únicos

If pvPrimeraLinea>pvUltimaLinea ;; No hay lista
  Calculate $cinst.$line as 0
  Quit Method 0
End If

If $cinst.[pvPrimeraLinea].[pvNombreColumna]=pvValor
  Calculate $cinst.$line as pvPrimeraLinea
  Quit Method pvPrimeraLinea
Else If pvPrimeraLinea=pvUltimaLinea|$cinst.[pvPrimeraLinea].[pvNombreColumna]>pvValor ;; No está en la lista
  Calculate $cinst.$line as 0
  Quit Method 0
End If

If $cinst.[pvUltimaLinea].[pvNombreColumna]=pvValue
  Calculate $cinst.$line as pvUltimaLinea
  Quit Method pvUltimaLinea
Else If pvPrimeraLinea+1=pvUltimaLinea|$cinst.[pvUltimaLinea].[pvNombreColumna];; No está en la lista
  Calculate $cinst.$line as 0
  Quit Method 0
End If

; Si se encuentra entre la primera y la última
Calculate lvLineaIntermedia as pvPrimeraLinea + ((pvUltimaLinea-pvPrimeraLinea)/2)
If lvLineaIntermedia=pvPrimeraLinea
  Calculate lvLineaIntermedia as lvLineaIntermedia+1
Else if lvLineaIntermedia=pvUltimaLinea ;; ¿Podría suceder?
  Calculate lvLineaIntermedia as lvLineaIntermedia-1
End If

If $cinst.[lvLineaIntermedia].[pvNombreColumna]=pvValor
  Calculate $cinst.$line as lvLineaIntermedia
  Quit Method lvLineaIntermedia
Else If $cinst.[lvLineaIntermedia].[pvNombreColumna]>pvValor
  ;  Localizada en la zona alta de la lista
 QuitMethod $cinst.$quickSearch(pvNombreColumna,pvValor,pvPrimeraLinea+1,lvLineaIntermedia-1)
Else
  ;  Localizada en la zona baja de la lista
 QuitMethod $cinst.$quickSearch(pvNombreColumna,pvValor,lvLineaIntermedia+1,pvUltimaLinea-1)
End If

Ahora podrá hacer uso del “quicksearch”, mediante simplemente hacer un:

Calculate lvValor as 'MiValorUnico'
Do lvMiLista.$quickSearch('MiColumna',lvValor)

No hay comentarios: