BotonMenu
BotonIndice

Visita : conoce3000.com
Paypal : https://www.paypal.com/donate/?hosted_button_id=XY8TZ3MGN64GE

PASCAL CON FREE PASCAL

PASCAL CON FREE PASCAL

PASCAL CON FREE PASCAL


13. LISTAS Y COLECCIONES.
13.3. CREANDO Y MANEJANDO COLECCIONES.
13. LISTAS Y COLECCIONES.
13.3. CREANDO Y MANEJANDO COLECCIONES.
13. LISTAS Y COLECCIONES.
13.3. CREANDO Y MANEJANDO COLECCIONES.

SIGUIENTE

SIGUIENTE

SIGUIENTE


‒ Creando y manejando colecciones.

Las colecciones TCollection, tienen los métodos y propiedades necesarios para su manipulación como son añadir, insertar, borrar elementos de una lista y otros más. Pero a diferencia de TFPList y Tlist, estos elementos deben ser clases heredadas de TColecctionItem.

Las colecciones se usan para representar listas de objetos que sean muy comunes entre ellos, como por ejemplo una lista de aviones, una lista de carros pero no una lista de aviones y mascotas. Es decir al momento de crear una colección, se debe definir cual será la clase padre al cual van a pertenecer todos los objetos de la colección. Esta clase padre debe ser siempre una subclase de la clase TCollectionItem.

En la siguiente tabla se explica brevemente algunos métodos de las colecciones TCollection.


Método Descripción
Create(i) Constructor modificado, que permite crear una colección. El parámetro i se usa para indicar la clase padre del cual serán los objetos de la colección.
Add Permite crear y añadir al final un objeto nuevo a la colección. Devuelve una instancia de la clase padre.
Insert(i) Permite crear e insertar un objeto nuevo en la posición indicada por i. Devuelve una instancia de la clase padre.
Delete(i) Borra o destruye un objeto descendiente de la clase padre, en la posición indicada por i.
Exchange(i,j) Permite intercambiar dos objetos de la colección indicados por i y j.
Clear Borra todos los objetos de la colección llamando a su destructor correspondiente.
Items[i] Es un atributo que nos permite acceder a un objeto. Si lo usamos para asignarlo a otro objeto de fuera de la colección devolverá un objeto de la clase TCollectionItem. Por ejemplo:

obj:=coleccion.items[3]

Es importante que obj, sea un objeto descendiente de la clase padre de la colección.

Pero si lo usamos para asignar un objeto a otro objeto de la colección este usará el método Assign para asignar los atributos del objeto. Por Ejemplo:

colección.items[3]:=obj;

Es importante que el objeto que se quiera asignar a un objeto de la colección sea descendiente de la clase padre de la colección y que el método Assign TCollectionItem deba ser sobrescrito, con los mecanismos para asignar sus atributos correspondientes.
Las colecciones se enumeran empezando con 0. Es decir el primer objeto de la colección es Items[0].
Count Es un atributo que nos indica la cantidad de objetos que tiene la colección.

Antes de crear una colección se debe definir la clase padre que se usará en la colección y esta debe heredar los atributos de TCollectionItem, cuando añadimos objetos a la colección se debe después añadir los atributos del objeto creado, para ello se debe usar un solapamiento con la clase padre de la colección. Ejemplo


Descargar
{$codepage utf8}
{$mode objfpc}
Uses sysutils,classes;

Type
    TInteger=class(TCollectionItem)
      public
       n:integer;
     End;

    TDouble=class(TCollectionItem)
      public
        n:double;
     End;

Var ColeccionN,ColeccionD:TCollection;
    n:TInteger;
    d:TDouble;
    i:byte;
Begin
  randomize;
  ColeccionN:=TCollection.create(TInteger);
  ColeccionD:=TCollection.create(TDouble);
  for i:=0 to 10 do
    begin
      n:=TInteger(ColeccionN.Add);
      d:=TDouble(ColeccionD.Add);
      n.n:=random(1000);
      d.n:=random;
    end;

  Writeln('ColeccionN');
  Writeln('Cantidad = ',ColeccionN.Count);
  for i:=0 to 10 do Writeln('[',i:2,'] ',TInteger(ColeccionN.items[i]).n);
  Writeln('Borrando');

  //Pone la lista a nil y la cantidad a 0 y también
  //ejecuta el método free de cada instancia de la colección
  ColeccionN.free;

  Writeln('ColeccionD');
  Writeln('Cantidad = ',ColeccionD.Count);
  for i:=0 to 10 do Writeln('[',i:2,'] ',TDouble(ColeccionD.items[i]).n:0:3);
  Writeln('Borrando');

  //Pone la lista a nil y la cantidad a 0 y 
  //también ejecuta el método free de cada instancia de la colección
  ColeccionD.free

End.
Código fuente 9: Creando y manejando colecciones.
Descargar

En el ejemplo anterior se crean dos colecciones una de números enteros y la otro de números reales, para eliminar las colecciones lo recomendado es ejecutar el método free de cada colección, y evitar el uso de destroy. Al borrar o destruir la colección no necesitamos eliminar cada objeto de la colección, estos se eliminan por el destructor de la colección. Es decir el destructor de una colección se encarga de destruir cada uno de los objetos de la colección. Si no queremos eliminar la colección y sólo sus objetos entonces se debe usar el método clear, este método solo elimina los objetos de la colección.

Cuando accedemos a los objetos de la colección siempre se debe usar el solapamiento con el tipo de dato de la clase padre de la colección, para poder acceder a sus atributos. Si deseamos hacer una colección de cadena de caracteres del tipo ansistring o unicodestring, debemos hacer una clase que contenga el tipo de dato ansistring o unicodestring, del mismo modo como se uso en el ejemplo anterior para los números enteros y reales del ejemplo anterior. El siguiente ejemplo es una colección de objetos de la clase padre TPersona, que se vio en el código fuente 3 del capitulo anterior. Ejemplo:


Descargar
{$codepage utf8}
{$mode objfpc}
Uses sysutils,classes;

Type
   TPersona=class(TCollectionItem)
    public
     Nombre,Ciudad:string;
     Procedure MostrarPersona;
   End;

   Procedure TPersona.MostrarPersona;
    Begin
      Writeln('Nombre:',Nombre);
      Writeln('Ciudad:',Ciudad)
    End;

Var Lista:TCollection;
    rpta:char;
    i:byte;
    Persona:TPersona;

Begin

  Lista:=TCollection.create(TPersona);

  Repeat
    Persona:=TPersona(Lista.Add);
    Write('Nombre : ');Readln(Persona.Nombre);
    Write('Ciudad : ');Readln(Persona.Ciudad);
    Write('Desea continuar [S]i [N]o : ');readln(rpta)
  Until (rpta='N') or (rpta='n');

  for i:=0 to lista.Count-1 do TPersona(Lista.items[i]).MostrarPersona;

  Writeln('Cantidad = ',Lista.Count);
  Writeln('Borrando');

  Lista.clear;
  Lista.destroy
End.
Código fuente 10: Coleccion con cadenas de caracteres con TPersona.
Descargar

El siguiente ejemplo muestra el uso de los métodos insert, delete, y exchange, en las colecciones no existe un método move, first y last. Pero el método move se puede implementar usando insert, delete y exchange, tomando en cuenta las siguientes consideraciones:

  • Si el origen es mayor que el destino, entonces se inserta un objeto en el destino, se intercambia el origen+1 con el destino, y se borra el origen+1
  • Si el origen es menor que el destino, entonces se inserta un objeto en el destino+1, se intercambia el origen con el destino+1, y se borra el origen.

A continuación el ejemplo:


Descargar
{$codepage utf8}
{$mode objfpc}
Uses sysutils,classes;

Type
   TCadenas=class(TCollectionItem)
    public
     Cad:ansistring;
     Constructor crear(ccad:ansistring);
   End;

   Constructor TCadenas.crear(ccad:ansistring);
     Begin
       cad:=ccad
     End;

Var Coleccion:TCollection;
    i:byte;
    micad:TCadenas;
Begin
  Coleccion:=TCollection.create(TCadenas);
  for i:=0 to 10 do
   Begin
     micad:=TCadenas(Coleccion.add);
     micad.crear('Numero '+intTostr(i))
   End;

  for i:=0 to Coleccion.Count-1 do
   Writeln('[',i:2,']',TCadenas(Coleccion.items[i]).cad);

  Writeln('======== INSERTANDO EN 5 ========');

  micad:=TCadenas(Coleccion.Insert(5));
  micad.Crear('Insertado');
  Writeln('Cantidad = ',Coleccion.Count);
  for i:=0 to Coleccion.Count-1 do 
    Writeln('[',i:2,']',TCadenas(Coleccion.items[i]).cad);

  Writeln('======== BORRANDO 5 ========');

  Coleccion.Delete(5);
  Writeln('Cantidad = ',Coleccion.Count);

  for i:=0 to Coleccion.Count-1 do
   Writeln('[',i:2,']',TCadenas(Coleccion.items[i]).cad);

  Writeln('======== INTERCAMBIANDO 1 con 4 ========');
  Coleccion.Exchange(1,4);
  for i:=0 to Coleccion.Count-1 do
   Writeln('[',i:2,']',TCadenas(Coleccion.items[i]).cad);

  Writeln('======== MOVIENDO 4 a 1 ========');
  //origen mayor que destino 4>1 => origen+1 y destino queda igual
  Coleccion.Insert(1); //inserta un objeto vacio
  Coleccion.Exchange(5,1);
  Coleccion.Delete(5);

  for i:=0 to Coleccion.Count-1 do
   Writeln('[',i:2,']',TCadenas(Coleccion.items[i]).cad);

  Writeln('======== MOVIENDO 2 a 4 ========');
  //origen menor que destino 2<4 => origen queda igual y destino+1
  Coleccion.Insert(5); //inserta un objeto vacio
  Coleccion.Exchange(2,5);
  Coleccion.Delete(2);
  for i:=0 to Coleccion.Count-1 do
   Writeln('[',i:2,']',TCadenas(Coleccion.items[i]).cad);


  Writeln('El primero elemento de la Coleccion es : ',
           TCadenas(Coleccion.Items[0]).cad);
  Writeln('El ultimo elemento de la Coleccion es : ',
           TCadenas(Coleccion.Items[Coleccion.Count-1]).cad);

  Coleccion.free
End.
Código fuente 11: Uso de insert, delete y exchange.
Descargar

En este ejemplo para añadir los objetos a la colección se hace uso de una clase padre que contiene un constructor, que nos permite colocar un contenido a la cadena de caracteres que tiene cada objeto.

Cuando insertamos un objeto a la colección en la posición indicada, los elementos a partir de la posición se desplazan todos a la siguiente, y como se puede observar al eliminar un objeto de la colección no es necesario eliminar el objeto individualmente como sucede cuando usamos listas, de eso se encarga el método Delete, que usamos para eliminar el objeto de la colección.

Los métodos Extract, Remove e IndexOf no tienen sentido que existan en una colección ya que los elementos de una colección no son simples punteros, pero existen situaciones en las que necesitamos extraer un objeto de una colección para colocarlo en otra, en esos casos debemos sobrescribir el método Assign de la clase TCollectionItems, para poder asignar los atributos de un objeto de una colección en otro y después borrar la anterior. El método Assign quedaría más o menos así:

Procedure TClasePadre.Assign(source:TPersistent);
    Begin
       if Source is TCadenas
       then cad := TCadenas(Source).cad
       else inherited Assign(Source);
    End;

TClasePadre se refiere a la clase que se usará para crear el objeto, y después cuando deseamos trasladar de una colección a otro podríamos hacer lo siguiente:

coleccion02.add;
coleccion02.items[coleccion02.Count-1]:=coleccion01.items[5];
coleccion01.delete(5);

El ejemplo completo lo pueden ver a continuación:


Descargar
{$codepage utf8}
{$mode objfpc}

Uses sysutils,classes;

Type

   TCadenas=class(TCollectionItem)
     public
      Cad:ansistring;
      procedure Assign(source:TPersistent);override;
   End;

   procedure TCadenas.Assign(source:TPersistent);
     Begin
       if Source is TCadenas then
          cad := TCadenas(Source).cad
       else
          inherited Assign(Source);
     End;

Var coleccion01,coleccion02:TCollection;
    aux:TCadenas;
    i:byte;
Begin
  Writeln('Coleccion 01');
  coleccion01:=TCollection.create(TCadenas);
  for i:=0 to 5 do
    Begin
     aux:=TCadenas(coleccion01.Add);
     aux.cad:='coleccion 01 '+intTostr(i)
    End;
  aux:=TCadenas(coleccion01.items[5]);

  //marcamos el objeto que queremos extraer
  aux.cad:='*'+aux.cad+'*';
  for i:=0 to coleccion01.Count-1 do
    Writeln('[',i:2,']',TCadenas(coleccion01.items[i]).cad);

  Writeln('Coleccion 02');
  coleccion02:=TCollection.create(TCadenas);
  for i:=0 to 5 do
    Begin
      aux:=TCadenas(coleccion02.Add);
      aux.cad:='coleccion 02 '+intTostr(i)
    End;
  for i:=0 to coleccion02.Count-1 do
    Writeln('[',i:2,']',TCadenas(coleccion02.items[i]).cad);

  coleccion02.add;
  coleccion02.items[6]:=coleccion01.items[5];
  coleccion01.delete(5);

  Writeln('Coleccion 01');
  for i:=0 to coleccion01.Count-1 do
    Writeln('[',i:2,']',TCadenas(coleccion01.items[i]).cad);
  Writeln('Coleccion 02');
  for i:=0 to coleccion02.Count-1 do
    Writeln('[',i:2,']',TCadenas(coleccion02.items[i]).cad)

End.
Código fuente 12: Uso de Assign.
Descargar

Las colecciones no tienen un método Addlist que permite añadir los elementos de una lista en otra lista. Las colecciones por el contrario tienen un método Assign, no confundir con el Assign de TColleccionItem. Este método permite crear objetos en una colección y asignar los objetos de otra colección al mismo tiempo, usando el método Assign propio de cada objeto de la otra colección.

Para poder hacerlo se debe modificar el método Assign de TCollectionItem como lo hicimos anteriormente y luego usar el método Assign de la colección, pero este método no permite unir dos colecciones en una, ya que si volvemos a usar el mismo método este borrara los anteriores objetos antes de asignar los nuevos. Para tal situación si queremos asignar más objetos debemos hacerlo con un bucle for que permita adicionar más objetos, usando el método Add. Ejemplo:


Descargar
{$codepage utf8}
{$mode objfpc}
Uses sysutils,classes;

Type
   TCadenas=class(TCollectionItem)
    public
     Cad:ansistring;
     Constructor crear(ccad:ansistring);
     procedure Assign(Source: TPersistent);override;
   End;

   Constructor TCadenas.crear(ccad:ansistring);
     Begin
       cad:=ccad
     End;

  procedure TCadenas.Assign(Source: TPersistent);
    begin
        if Source is TCadenas then
          cad := TCadenas(Source).cad
        else
          inherited Assign(Source);
    end;

Var coleccion01,coleccion02,coleccion03:TCollection;
    i:byte;
    aux:TCadenas;
Begin
  coleccion01:=TCollection.create(TCadenas);
  for i:=0 to 10 do
    Begin
     aux:=TCadenas(coleccion01.add);
     aux.crear('Numero '+intTostr(i));
    End;

  coleccion02:=TCollection.create(TCadenas);
  for i:=11 to 20 do
    Begin
     aux:=TCadenas(coleccion02.add);
     aux.crear('Numero '+intTostr(i));
    End;

  coleccion03:=TCollection.create(TCadenas);
  coleccion03.Assign(coleccion01);
  //Saca una copia de todos los objetos de coleccion01 y
  //los coloca en coleccion03, el resto se hace manualmente
  for i:=0 to coleccion02.Count-1 do
    Begin
      aux:=TCadenas(coleccion03.add);
      aux.Assign(coleccion02.items[i])
    End;

  coleccion01.clear;
  coleccion02.clear;

  for i:=0 to coleccion03.Count-1 do Writeln(TCadenas(coleccion03.items[i]).cad);

End.
Código fuente 13: Uso de Assign de TCollection.
Descargar

En el ejemplo se puede observar el uso del bucle for, en el cual se hace un recorrido por todos los objetos de la colección02, para ir añadiéndolos a la coleccion03.

Hay situaciones en las que necesitamos extraer un objeto de la colección y que este ya no este en ella, para ello debemos de crear un objeto de la clase padre que lo contenga, para borrarlo posteriormente de la colección. El método create de la clase padre es un constructor sobrescrito de TCollectionItem, que usa un parámetro de tipo TCollection, que se usa para indicarle en que colección se debe añadir el objeto. El constructor se puede usar también para añadir objetos a una colección, pero si queremos crear un objeto de la clase padre, sin añadirlo a una colección debemos colocar nil como parámetro del método create, para indicarle que este objeto no pertenece a ninguna colección. A continuación el ejemplo.


Descargar
{$codepage utf8}
{$mode objfpc}

Uses sysutils,classes;

Type

   TCadenas=class(TCollectionItem)
     public
      Cad:ansistring;
      procedure Assign(source:TPersistent);override;
   End;


   procedure TCadenas.Assign(source:TPersistent);
     Begin
       if Source is TCadenas then
          cad := TCadenas(Source).cad
       else
          inherited Assign(Source);
     End;

Var coleccion01:TCollection;
    aux:TCadenas;
    i:byte;
Begin
  Writeln('Coleccion 01');
  coleccion01:=TCollection.create(TCadenas);
  for i:=0 to 5 do
    Begin
      aux:=TCadenas.create(coleccion01);
      aux.cad:='coleccion 01 '+intTostr(i)
    End;
  aux:=TCadenas(coleccion01.items[5]);
  //marcamos el objeto que queremos extraer
  aux.cad:='*'+aux.cad+'*';
  for i:=0 to coleccion01.Count-1 do Writeln('[',i:2,']',TCadenas(coleccion01.items[i]).cad);

  aux:=TCadenas.create(nil);
  aux.Assign(coleccion01.items[5]);
  coleccion01.delete(5);

  Writeln('Coleccion 01');
  for i:=0 to coleccion01.Count-1 do Writeln('[',i:2,']',TCadenas(coleccion01.items[i]).cad);
  Writeln('aux = ',aux.cad);

  coleccion01.free
End.
Código fuente 14: Extraer un objeto de una colección.
Descargar

En el ejemplo anterior se puede observar que para añadir nuevos objetos a la colección, se hace uso del constructor en ves de usar el método Add.

Al igual que las listas también se pueden usar los bucles for in loop, para ello se necesita de una variable de control que sea un objeto de la clase que se usa en la colección. Es decir el siguiente bucle:

for i:=0 to 10 do Writeln('[',i:2,'] ',Tinteger(ColeccionN.items[i]).n);

en donde Tinteger es la clase de todos los objetos de ColeccionN, se puede escribir del siguiente modo usando for-in-loop:

for TCollectionItem(n) in ColeccionN do Writeln('[',n.index:2,']',n.n);

En donde n es un objeto de la clase Tinteger al que se le hace un solapamiento con TCollectionItem, ya que el bucle for-in-loop espera que la variable de control sea un TCollectionItem cuando este trabaja con Colecciones. Aquí también se puede observar el uso del atributo index, este atributo es una herencia de TCollectionItem, y contiene el indice que le corresponde en la colección al objeto. El siguiente código fuente es el mismo ejemplo01 pero este hace uso de for-in-loop.


Descargar
{$codepage utf8}
{$mode objfpc}
Uses sysutils,classes;

Type
    TInteger=class(TCollectionItem)
      public
       n:integer;
     End;

    TDouble=class(TCollectionItem)
      public
        n:double;
     End;

Var ColeccionN,ColeccionD:TCollection;
    n:TInteger;
    d:TDouble;
    i:byte;
Begin
  randomize;
  ColeccionN:=TCollection.create(TInteger);
  ColeccionD:=TCollection.create(TDouble);
  for i:=0 to 10 do
    begin
      n:=TInteger(ColeccionN.Add);
      d:=TDouble(ColeccionD.Add);
      n.n:=random(1000);
      d.n:=random;
    end;

  Writeln('ColeccionN');
  Writeln('Cantidad = ',ColeccionN.Count);

  for TCollectionItem(n) in ColeccionN do Writeln('[',n.index:2,']',n.n);
  Writeln('Borrando');

  ColeccionN.free;

  Writeln('ColeccionD');
  Writeln('Cantidad = ',ColeccionD.Count);

  for TCollectionItem(d) in ColeccionD do Writeln('[',d.index:2,']',d.n:0:3);
  Writeln('Borrando');

  ColeccionD.free
End.
Código fuente 15: Uso de for in loop con colecciones.
Descargar




SIGUIENTE
SIGUIENTE
SIGUIENTE


 
‒ Comentarios y sugerencias.

Agradezco de antemano, todo comentario, sugerencia, y donativo a través de , que ayude a mejorar los contenidos educativos de Conoce 3000. Además, cualquier pregunta o duda que tengas lo puedes hacer por este medio. Pero, todo contenido que pueda resultar ofensivo, malicioso, racista, sexista, discriminatorio, obsceno, vulgar será eliminado. Para clases particulares contactame por whatsapp al 📲 (+51) 999 264 073








PORTADA |  INTERESANTE |  APUNTES |  LIBROS |  GALERIA


Creative Commons License


Todos los textos, imágenes y videos de Conoce3000 estan colocados bajo una licencia : Creative Commons Reconocimiento-NoComercial 3.0 Unported License.