Foros Club Delphi

Foros Club Delphi (https://www.clubdelphi.com/foros/index.php)
-   Varios (https://www.clubdelphi.com/foros/forumdisplay.php?f=11)
-   -   ¿Como comparar 2 record? (https://www.clubdelphi.com/foros/showthread.php?t=89136)

geolife 01-10-2015 18:54:01

¿Como comparar 2 record?
 
Estimados amig@s,

Tengo una base de datos de clientes basada en un TStringList asociada a un TCliente en forma de record y necesito comparar 2 registros. Como son muchos campos, me pregunto si existe alguna forma de comparar 2 bloques de memoria de una sola vez o usando algún automatismo, sin necesidad de preguntar campo a campo, lo que resulta muy engorroso.

Ejemplo:
Contamos con un registro tipo cliente...
Código Delphi [-]
// El caso real cuenta con más de 60 campos
TCliente = Record
  Campo1: String; 
  Campo2: Double;
  Campo3: TdateTime;
end;

Function Es_Igual (A,B: TCliente): Boolean;
begin
  A.Campo1 := 'Juan';
  A.Campo2 := 1000;
  B.Campo1 := 'Sebas';
  B.Campo2 := 1000;

  // No podemos hacer lo siguiente; Result :=  A = B;
  // He probado esta alternativa pero siempre obtengo el mismo resultado, son iguales;
  Result := CompareMem(@A, @B, SizeOf(TCliente));
end;
En fin, algo debo hacer mal!!:confused:

Saludos!

Silvestre

mamcx 01-10-2015 19:30:25

Lo de comparar los punteros de memoria tiene sentido si quieres saber si los punteros son o no iguales.

Pero como quieres saber si los "valores" son o no iguales, entonces solo queda comparar valores. Eso significa, que si, tienes que comparar campo a campo hasta que encuentres uno diferente (o si necesitas saber cuales, acumular los campos dispares en una lista). Eso no tiene otro camino.

Si solo te interesa saber si son diferentes pero no porque, puedes acelerar el proceso guardando en un campo extra un hash de la suma de todos los campos cada vez de hacer insert/delete, y solo comparas los hash después.

geolife 01-10-2015 19:43:26

Gracias Mammx!,

Si, en este caso solo es necesario saber que son diferentes, pero no donde están las diferencias.

Para crear un campo que contiene el hash de la totalidad de los campos que deseamos comparar, supongo que hay que implementarlo también uno a uno, ¿Se podría recorrer los campos de un record? como hacemos con los objetos de un componente en el ejemplo de abajo...
Código Delphi [-]
Procedure Recorrer_Controles;
var
  i:integer;
  Hash: String;
begin
  for I:= 0 to PageControl.ControlCount - 1 do
    if (PageControl.Controls[i] is TEdit) then Hash := Hash + ' | '+  (PageControl.Controls[i] as Tedit).Text;
end;
Cita:

Empezado por mamcx (Mensaje 497463)
Lo de comparar los punteros de memoria tiene sentido si quieres saber si los punteros son o no iguales.

Pero como quieres saber si los "valores" son o no iguales, entonces solo queda comparar valores. Eso significa, que si, tienes que comparar campo a campo hasta que encuentres uno diferente (o si necesitas saber cuales, acumular los campos dispares en una lista). Eso no tiene otro camino.

Si solo te interesa saber si son diferentes pero no porque, puedes acelerar el proceso guardando en un campo extra un hash de la suma de todos los campos cada vez de hacer insert/delete, y solo comparas los hash después.


ecfisa 01-10-2015 21:10:10

Hola geolife.

Si estas usando Delphi 2010 o superior, revisa este enlace: List the Record's element\fields

Saludos :)

geolife 01-10-2015 22:00:03

Hola ecfisa,

Si! Hace poco tiempo compre una licencia de Delphi XE7 y no estaba al corriente de esta mejora en la rtti. Esto aumenta en gran medida la capacidad de trabajar con registros de elementos. :):):)

Muchas gracias como siempre por vuestra ayuda. ecfisa, mamcx, casimiro!! ^\||/

Cita:

Empezado por ecfisa (Mensaje 497473)
Hola geolife.
Si estas usando Delphi 2010 o superior, revisa este enlace: List the Record's element\fields

Saludos :)


Al González 01-10-2015 22:04:46

Además de la interesante aportación de Rodrigo Ruz indicada puntualmente por ecfisa, considera algún mecanismo de serialización que facilite el proceso de comparar. Serializar se puede entender de forma simple como convertir cualquier grupo de información estructurada en una tira plana de bytes sin punteros (los campos String son punteros a otra región de memoria). Como tal, esa tira de bytes será perfectamente comparable mediante la función CompareMem. Sólo considera que esto puede ser más lento que comparar campo por campo o que usar códigos Hash.

Como sea, y viendo que tienes una versión moderna de Delphi, tiene mucho valor estudiar temas de RTTI y clases novedosas como TBinaryWriter.

Un saludo. :)

geolife 01-10-2015 22:22:19

Hola Al,

Entiendo según tu explicación que para poder usar la función CompareMen usando serialización lo que tengo que hacer es fabricar una estructura con longitud fija, es decir, si uso algún String del que puedo conocer su rango de uso, podría codificar algo como:

Código Delphi [-]
TCliente = Record
  Campo1: String[30]; 
  Campo2: Double;
  Campo3: TdateTime;
end;

Gracias! ^\||/


Cita:

Empezado por Al González (Mensaje 497475)
Además de la interesante aportación de Rodrigo Ruz indicada puntualmente por ecfisa, considera algún mecanismo de serialización que facilite el proceso de comparar. Serializar se puede entender de forma simple como convertir cualquier grupo de información en una tira plana de bytes sin punteros (los campos String son punteros a otra región de memoria). Como tal, esa tira de bytes será perfectamente comparable mediante la función CompareMem. Sólo considera que esto puede ser más lento que comparar campo por campo o que usar códigos Hash.

Como sea, y viendo que tienes una versión moderna de Delphi, tiene mucho valor estudiar temas de RTTI y clases novedosas como TBinaryWriter.

Un saludo. :)



La franja horaria es GMT +2. Ahora son las 09:27:31.

Powered by vBulletin® Version 3.6.8
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
Traducción al castellano por el equipo de moderadores del Club Delphi