Buscar un elemento dentro de un SDT en GeneXus
En GeneXus, no hay una forma de buscar un elemento dentro de una colección (SDT), que no sea recorriendo toda la lista. Hay una función IndexOf, pero compara referencias y no el contenido de los elementos.
Ejemplo:
El problema es que dado un SDT, GeneXus no tiene forma de saber cuales son los elementos que quiero comparar. En el ejemplo, estoy comparando DepId y CicUbiId, pero el SDT tiene varios campos más.
Una posibilidad sería poder definirle comportamiento a los SDTs, de forma de poder decirle cual es la función de comparación que tengo que usar. Esta función de comparación se definiría una vez para el SDT, y siempre que se quiera buscar un elemento se haría usando este comparador.
Otra opción que me gustaría más, es poder definir on-line la función de comparación. En C# por ejemplo, usando lambda expressions, quedaría algo así:
Las colecciones en C# definen otras funciones que también sería intereante tener, como ser:
Ejemplo:
&esta = Boolean.FalseEsto no parece ser lo más elegante... No debería necesitar 7 líneas de código para saber si un elemento está en la colección, lo debería poder hacer en una sola línea.
for &depUbiItem in &depUbis
if &depUbiItem.DepId = &DepId and &depUbiItem.CicUbiId = &CicUbiId
&esta = Boolean.True
exit
endif
endfor
El problema es que dado un SDT, GeneXus no tiene forma de saber cuales son los elementos que quiero comparar. En el ejemplo, estoy comparando DepId y CicUbiId, pero el SDT tiene varios campos más.
Una posibilidad sería poder definirle comportamiento a los SDTs, de forma de poder decirle cual es la función de comparación que tengo que usar. Esta función de comparación se definiría una vez para el SDT, y siempre que se quiera buscar un elemento se haría usando este comparador.
Otra opción que me gustaría más, es poder definir on-line la función de comparación. En C# por ejemplo, usando lambda expressions, quedaría algo así:
bool esta = depUbis.Exists(d => ((d.DepId = depId) && (d.CicUbiId = cicUbiId)));O escribiendolo como me gustaría verlo en GeneXus:
&esta = &depUbis.Exists(d => d.DepId = &DepId and d.CicUbiId = &CicUbiId)Esto se lee "existe un elemento d en la colección &depUbis que cumple que d.DepId = &DepId y d.CicUbiId = &CicUbiId".
Las colecciones en C# definen otras funciones que también sería intereante tener, como ser:
- First: devuelve el primer elemento que cumple con la condición
- Where: devuelve otra colección con los elementos que cumplen con la condición
- Select: permite hacer una proyección, devuelve otra colección pero de otro tipo
Muy buena idea. :)
ResponderBorrarSin embargo no te parece mejor idea la de unificar la navegación de SDT's/Collections/Vectores con nuestro querido For Each? van mis sugerencias.
1 - Que la navegación SDT sea igual que la navegación sobre Tablas = Unificación de lenguaje.
Usar For Each para SDT's/Collections/Vec con soporte de todo el poder del lenguaje (Order, Where, When), que luego GX vea cómo lo expresa en lenguaje generado.
For Each in &depUbis
Where DepId = &DepId and CicUbiId = &CicUbiId
&esta = Boolean.True
Exit
EndFor
2 - Algo que desde hace tiempo hace falta, el Exists y el "TOP n Registros", aplicado al For Each
&Exist = For Each Exists in &depUbis Where DepId = &DepId and CicUbiId = &CicUbiId
Internamente el Exist vería si retorna por lo menos 1 elemento la colección o para el caso del DBMS si existe 1 registro por lo menos (TOP 1, pero ideal sería sin retornarlo)
De la misma forma, para navegación entre Tablas que permita el mismo concepto y que a nivel de sentencias se optimizado para cada DBMS (Con top o consulta de existencia nativa)
3 - Para el caso del TOP podría ser algo como.
For Each TOP(10) in &depUbis
Where DepId = &DepId and CicUbiId = &CicUbiId
Order by (DepSize)
Print TOP_10
EndFor
Para este caso internamente se ordenaría la colección con orden invertido y se tomarían solamente 10 registros.
Si fuera para DBMS, el TOP debería ir contra sentencia nativa indicando al DBMS que solamente retorne la cantidada X de registros, de esta forma si tengo 1 millon de registros entre el dbms y el appserver solo viajarán 10 registros dejando al DBMS la tarea de filtrado.
La implementación de FOR EACH FIRST se podría hacer igual al FOR EACH TOP(1)
Con las extensiones al For Each y la inclusión de For Each para todo tipo de elemento navegable sería feliz :-)
Lo evaluarán Artech para la EVO II o EVO III?
David, están buenas tus sugerencias, también me sirven.
ResponderBorrarNo se si lo evaluarán, pero por lo menos el planteo está hecho :)
Me anoto a la sugerencia de David.
ResponderBorrarCon el for each y el where quedaria muy bueno!
También me anoto a la sugerencia de hacer un for each de una colección de SDT con un where, estaría sinceramente interesante.
ResponderBorrarHola gente
ResponderBorrary ya que estamos, sumo algunas ideas
1- quizá se le pueda agregar una PK al SDT o una especie de indice unique y nos solucionaría mas de un dolor de cabeza.
2 - Sumada a (1) implemetar clausula When Duplicate al agregar un elemento al SDT y when none al usar el recorrerlo.
3- Y creo que la tercera cae sola...ya es hora de poder hacer un break dentro de los SDT anidando un par de For each.
con ésto mas las que ya aportó el resto, incrementaríamos la potencia un 100 x 100.
Saludos
Franco, buenas sugerencias!!
ResponderBorrarHace un rato charlaba sobre el tema con un compañero de trabajo (Marcos) y saltó justamente lo que mencionaste en el punto 1, la necesidad de tener algo como una PK o "KEY".
Punto 2 y 3 estaría bárbaro.
Hola David!, recuerdo haberlo sugerido hace unos años, con gx8 ni bien trabajé con los SDT. Nos hubiese resuelto entre otras cosas, evitar armar tablas 'temporales' cuando no podíamos resolver de forma natural el orden de algún reporte, pero la idea nunca prosperó y aun hoy veo que siguen siendo buenas sugerencias.
ResponderBorrarCasualmente hoy necesito armar bandejas de salida para MasterCard y un SDT con PK evitaría que tenga que armar una tabla...;tabla que debo cambiar cada vez que master modifica el diseño de sus registros, jeje. En una de esas esta vez tenemos mas suerte!
Lo de tener SDT con claves, se habia discutido en el foro de la rocha y me habia dicho Gustavo Proto que era una mejora importante y que no iba a estar para la rocha (X).
ResponderBorrarCreo que es una funcionalidad muy util y seria bueno seguir investigando su factibilidad.
El link http://www.gxopen.com/forumsr/servlet/viewthread?ARTECH,22,126696
El “lenguaje” carece de estructuras de datos y debería proporcionar más funciones que faciliten su funcionamiento. El dar rodeos acerca de algo que debería ser sencillo es una pérdida de tiempo.
ResponderBorrarAunque debo de aceptar que el que Genexus permita incrustar código Java o C# es de lo más útil para quitar las muchas limitantes que esta herramienta posee.