Las listas tanto TList como TFPList, 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. TList y TFPList son clases que permiten en realidad manejar o manipular un arreglo de punteros. En la siguiente tabla se explica brevemente algunos de ellos.
Método |
Descripción |
Add |
Permite añadir un puntero a la lista. |
Insert(i) |
Permite insertar un puntero a la lista, en la posición indicada por i |
Delete |
Pone a Nil un puntero de la lista. |
Exchange(i,j) |
Permite intercambiar dos punteros de la lista indicados por i y j. |
Move(i,j) |
Permite mover un puntero de la posición i a la posición indicada por j, en la lista. |
First |
Permite obtener el primer puntero diferente a nil de la lista. |
Last |
Permite obtener el último puntero diferente a nil de la lista. |
Clear |
Borra sólo la lista de punteros, pero no las variables dinámicas o objetos a los que apuntan cada puntero de la lista. |
Pack |
Permite liberar espacio ocupado por los punteros de la lista que tengan nil. |
Items[i] |
Es una atributo que nos permite acceder a un puntero de la lista indicado por el indice i. La listas se enumeran empezando con 0. Es decir el primer elemento de la lista es Items[0]. |
Capacity |
Es un atributo que nos indica la cantidad de punteros que puede usar la lista. |
Count |
Es un atributo que nos indica la cantidad de punteros que tiene la lista. |
Debido a que TList y TFPList manejan un arreglo de punteros cada vez que queremos acceder a uno de los elementos de la lista, se debe hacer un solapamiento con el tipo de dato correspondiente. Además se debe tener presente que antes de borrar una lista o destruir una lista, se debe borrar todas las variables dinámicas a las que apuntan los punteros de la lista, ya que si no estos se quedarán ocupando espacio mientras duré la ejecución del programa. Ejemplo:
‒
Descargar
{$codepage utf8}
{$mode objfpc}
Uses sysutils,classes;
Var ListaN,ListaD:Tlist;
n:^integer;
d:^double;
i:byte;
Begin
randomize;
ListaN:=Tlist.create;
ListaD:=Tlist.create;
for i:=0 to 10 do
begin
new(n);new(d);
n^:=random(1000);
d^:=random;
ListaN.add(n);
ListaD.add(d);
end;
Writeln('ListaN');
Writeln('Capacidad = ',ListaN.Capacity);
Writeln('Cantidad = ',ListaN.Count);
for i:=0 to 10 do Writeln('[',i:2,'] ',integer(ListaN.items[i]^));
Writeln('Borrando');
//Si no usamos freemem para eliminar las variables dinámicas
//n estaría apuntando a la última variable dinámica creada.
for i:=0 to 10 do freemem(ListaN.items[i]);
//Pone la lista a nil y la cantidad a 0
ListaN.clear;
ListaN.destroy;
Writeln('ListaD');
Writeln('Capacidad = ',ListaD.Capacity);
Writeln('Cantidad = ',ListaD.Count);
for i:=0 to 10 do Writeln('[',i:2,'] ',double(ListaD.items[i]^):0:3);
Writeln('Borrando');
//Si no usamos freemem para eliminar las variables dinámicas
//d estaría apuntando a la última variable dinámica creada.
for i:=0 to 10 do freemem(ListaD.items[i]);
//Pone la lista a nil y la cantidad a 0
ListaD.clear;
ListaD.destroy;
End.
Código fuente 1: Creando y manejando un lista.
Descargar
En el ejemplo anterior se crean dos listas una de números enteros y la otro de números reales, para eliminar las variables dinámicas se hace uso de freemem y no de dispose, esto es debido a que los elementos de la lista son punteros sin tipo, es decir son del tipo pointer.
Si deseamos hacer una lista de cadena de caracteres del tipo ansistring o unicodestring, debemos hacer un artificio, ya que estos tipos de datos a pesar de ser variables dinámicas se comportan como variables estáticas de tipo string. El artificio consiste en crear un puntero a un registro que contenga una cadena de caracteres como uno de sus campos. Y el puntero a registro es el que se va colocando a la lista. Ejemplo:
‒
Descargar
{$codepage utf8}
{$mode objfpc}
Uses sysutils,classes;
Type TCad=Record
cad:unicodestring
End;
Var Lista:Tlist;
i:byte;
Pcad:^TCad;
Begin
randomize;
Lista:=Tlist.create;
for i:=0 to 10 do
begin
new(Pcad);
Pcad^.cad:='Numero '+IntToStr(random(1000));
Lista.add(Pcad);
end;
for i:=0 to 10 do writeln(TCad(Lista.items[i]^).cad);
Writeln('Capacidad = ',Lista.Capacity);
Writeln('Cantidad = ',Lista.Count);
Writeln('Borrando');
for i:=0 to 10 do freemem(Lista.items[i]);
Lista.clear;
Lista.destroy
End.
Código fuente 2: Lista con cadena de caracteres.
Descargar
Debido a que una instancia o objeto de una clase en realidad es un puntero a una estructura que representa una clase, estos también se pueden usar con listas, pero al momento de usar una elemento de la lista debemos hacer el solapamiento con el tipo de dato de la clase. Ejemplo:
‒
Descargar
{$codepage utf8}
{$mode objfpc}
Uses sysutils,classes;
Type
TPersona=class
Nombre,Ciudad:string;
Procedure MostrarPersona;
End;
Procedure TPersona.MostrarPersona;
Begin
Writeln('Nombre:',Nombre);
Writeln('Ciudad:',Ciudad)
End;
Var Lista:Tlist;
rpta:char;
i:byte;
Persona:TPersona;
aux:pointer;
Begin
Lista:=Tlist.create;
Repeat
Persona:=TPersona.create;
Write('Nombre : ');Readln(Persona.Nombre);
Write('Ciudad : ');Readln(Persona.Ciudad);
Lista.add(Persona);
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('Capacidad = ',Lista.Capacity);
Writeln('Cantidad = ',Lista.Count);
Writeln('Borrando');
//Si no usamos destroy para eliminar las instancias
//estas estarán ocupando memoria RAM en la computadora.
for i:=0 to lista.Count-1 do TPersona(Lista.items[i]).destroy;
Lista.clear;
Lista.destroy
End.
Código fuente 3: Lista con objetos.
Descargar
Tal como se puede observar del ejemplo anterior, no se puede usar freemem para borrar las instancias o los objetos colocados en la lista, se debe usar el destructor correspondiente del objeto, que en este caso es destroy. En cualquier caso cuando se manejan listas y se deben eliminar algún elemento de la lista se debe eliminar antes la variable dinámica u objeto al que apunta el puntero de la lista.
El siguiente ejemplo muestra el uso de los métodos insert, delete, exchange, move, first, last y pack.
‒
Descargar
{$codepage utf8}
{$mode objfpc}
Uses sysutils,classes;
Type
TCadenas=class
Cad:ansistring;
Constructor crear(ccad:ansistring);
End;
Constructor TCadenas.crear(ccad:ansistring);
Begin
cad:=ccad
End;
Var Lista:Tlist;
i:byte;
Begin
Lista:=Tlist.create;
for i:=0 to 10 do Lista.add(TCadenas.crear('Numero '+intTostr(i)));
for i:=0 to lista.Count-1 do Writeln('[',i:2,']',TCadenas(Lista.items[i]).cad);
Writeln('======== INSERTANDO EN 5 ========');
//inserta el elemento en la posición 5, el que se encuentra en esa
//posición se desplaza a la siguiente
Lista.Insert(5,TCadenas.Crear('insertado'));
Writeln('Capacidad = ',Lista.Capacity);
Writeln('Cantidad = ',Lista.Count);
for i:=0 to lista.Count-1 do Writeln('[',i:2,']',TCadenas(Lista.items[i]).cad);
Writeln('======== BORRANDO 5 ========');
//Se debe destruir antes de borrar el elemento de la lista
//Borra el elemento en la posición 5, pone el puntero a nil,
//no borra a lo que apunta el puntero o la instancia de una clase.
TCadenas(Lista.items[5]).destroy;
Lista.Delete(5);
Writeln('Capacidad = ',Lista.Capacity);
Writeln('Cantidad = ',Lista.Count);
for i:=0 to lista.Count-1 do Writeln('[',i:2,']',TCadenas(Lista.items[i]).cad);
Writeln('======== INTERCAMBIANDO 1 con 4 ========');
Lista.Exchange(1,4);
for i:=0 to lista.Count-1 do Writeln('[',i:2,']',TCadenas(Lista.items[i]).cad);
Writeln('======== MOVIENDO 4 a 1 ========');
Lista.Move(4,1);
for i:=0 to lista.Count-1 do Writeln('[',i:2,']',TCadenas(Lista.items[i]).cad);
Writeln('======== MOVIENDO 2 a 4 ========');
Lista.Move(2,4);
for i:=0 to lista.Count-1 do Writeln('[',i:2,']',TCadenas(Lista.items[i]).cad);
Writeln('El primero elemento de la lista es : ',TCadenas(Lista.First).cad);
Writeln('El ultimo elemento de la lista es : ',TCadenas(Lista.Last).cad);
Lista.pack;
Lista.destroy
End.
Código fuente 4: Uso de insert, delete, exchange, move, first, last y pack.
Descargar
En este ejemplo para añadir los elementos a la lista se hace uso de una clase que contiene un constructor, que nos permite colocar un contenido a la cadena de caracteres que la clase contiene. Cuando insertamos un puntero u objeto a la lista en la posición indica los elementos a partir de la posición se desplazan todos a la siguiente, y como se puede observar al eliminar un elemento de la lista debemos de eliminar la variable dinámica o objeto al que apunta el puntero, ya que cuando se usa el método delete, lo que se hace es poner a nil el puntero.
Otros métodos que tienen Tlist y TFPList son Extract, Remove y IndexOf, estos necesitan como parámetro un puntero, la siguiente tabla describe su funcionamiento.
Método |
Descripción |
Extrac(p) |
Coloca a nil el primer puntero p, que encuentre en la lista y devuelve el puntero encontrado para su posterior uso. |
Remove(p) |
Coloca a nil el primer puntero p, que encuentre en la lista y devuelve la posición en donde fue encontrado, en caso no lo encontró devuelve un -1. |
IndexOf(p) |
Busca el primer puntero p, que encuentre en la lista y devuelve la posición en donde fue encontrado, en caso no lo encontró devuelve un -1. |
Aunque obviamente no es muy natural para el ser humano buscar punteros en una lista, estos métodos se suelen usar para buscar objetos en la lista, y se suele usar cuando hay varias listas y se desea saber si un objeto se encuentra en una lista o en la otra. Por ejemplo el método extract devuelve el objeto encontrado (es decir el puntero), y su uso posterior puede ser colocarlo en otra lista, y en el caso del método Remove, que devuelve la posición en donde encontró el puntero se puede usar simplemente para borrar el objeto de la lista porque este ya se encuentra en otra lista. Ejemplo:
‒
Descargar
{$codepage utf8}
{$mode objfpc}
Uses sysutils,classes;
Type
TCadenas=class
Cad:ansistring;
Constructor crear(ccad:ansistring);
End;
Constructor TCadenas.crear(ccad:ansistring);
Begin
cad:=ccad
End;
Var Lista01,Lista02,Lista03:Tlist;
aux:pointer;
i:byte;
Begin
Lista01:=Tlist.create;
Lista02:=Tlist.create;
Lista03:=Tlist.create;
Writeln('=====LISTA01=====');
Lista01.Add(TCadenas.crear('Juan'));
Lista01.Add(TCadenas.crear('Jose'));
Lista01.Add(TCadenas.crear('Miguel'));
Lista01.Add(TCadenas.crear('Ana'));
for i:=0 to lista01.Count-1 do Writeln('[',i:2,']',TCadenas(Lista01.items[i]).cad);
Writeln('=====LISTA02=====');
Lista02.Add(Lista01.items[2]); //Miguel
Lista02.Add(TCadenas.crear('Sofia'));
Lista02.Add(TCadenas.crear('Mary'));
Lista02.Add(Lista01.items[0]); //Juan
for i:=0 to lista02.Count-1 do Writeln('[',i:2,']',TCadenas(Lista02.items[i]).cad);
Writeln('=====LISTA03=====');
Lista03.Add(Lista02.items[2]); //Mary
Lista03.Add(TCadenas.crear('Grace'));
Lista03.Add(TCadenas.crear('Luis'));
Lista03.Add(Lista01.items[0]); //Juan
for i:=0 to lista03.Count-1 do Writeln('[',i:2,']',TCadenas(Lista03.items[i]).cad);
Writeln('Buscando a Juan en la lista 02 y lista 03');
aux:=Lista01.items[0];
if Lista02.indexof(aux)>=0 then
Writeln('Esta en la lista 02')
else writeln('no se encontro en lista02');
if Lista03.indexof(aux)>=0 then
Writeln('Esta en la lista 03')
else writeln('no se encontro en lista03');
Writeln('Buscando a Grace en la lista 01 y lista 02');
aux:=Lista03.items[1];
if Lista01.indexof(aux)>=0 then
Writeln('Esta en la lista 01')
else writeln('no se encontro en lista01');
if Lista02.indexof(aux)>=0 then
Writeln('Esta en la lista 02')
else writeln('no se encontro en lista02');
Writeln('Borrando a Mary de lista03 para ponerlo en la lista 01');
aux:=Lista03.Extract(Lista02.items[2]);
Lista01.add(aux);
Writeln('=====LISTA03=====');
for i:=0 to lista03.Count-1 do
Writeln('[',i:2,']',TCadenas(Lista03.items[i]).cad);
Writeln('=====LISTA01=====');
for i:=0 to lista01.Count-1 do
Writeln('[',i:2,']',TCadenas(Lista01.items[i]).cad);
Writeln('Borrando a Juan de la lista03, pero dejandolo en lista01');
Lista03.remove(Lista01.items[0]);
Writeln('=====LISTA03=====');
for i:=0 to lista03.Count-1 do
Writeln('[',i:2,']',TCadenas(Lista03.items[i]).cad);
Writeln('=====LISTA01=====');
for i:=0 to lista01.Count-1 do
Writeln('[',i:2,']',TCadenas(Lista01.items[i]).cad);
End.
Código fuente 5: Uso de extract, remove y indexof.
Descargar
Otro método que es muy útil en las listas y bastante fácil de entender es el método Addlist, lo que hace este método es añadir todos los punteros de otra lista en la lista del método que lo contienen. Ejemplo:
‒
Descargar
{$codepage utf8}
{$mode objfpc}
Uses sysutils,classes;
Type
TCadenas=class
Cad:ansistring;
Constructor crear(ccad:ansistring);
End;
Constructor TCadenas.crear(ccad:ansistring);
Begin
cad:=ccad
End;
Var Lista01,lista02,lista03:Tlist;
i:byte;
Begin
Lista01:=Tlist.create;
for i:=0 to 10 do Lista01.add(TCadenas.crear('Numero '+intTostr(i)));
Lista02:=Tlist.create;
for i:=11 to 20 do Lista02.add(TCadenas.crear('Numero '+intTostr(i)));
Lista03:=Tlist.create;
Lista03.AddList(Lista01);
Lista03.AddList(Lista02);
for i:=0 to lista03.Count-1 do Writeln(TCadenas(Lista03.items[i]).cad);
End.
Código fuente 6: Uso de Addlist.
Descargar
En los ejemplos anteriores hemos recorrido las listas usando un for desde 0 hasta Count-1, esto se puede abreviar o hacer de un modo más cómodo con el uso de un bucle for in loop.
La clase Tlist y TFPList están diseñadas para trabajar con este bucle, sólo se necesita crear una variable de control de tipo pointer, para recorrer la lista con el bucle for in loop. Es decir algo como esto :
for i:=0 to Lista01.Count-1 do Writeln(Integer(ListaN.items[i]^))
se puede escribir de la siguiente manera:
for aux in ListaN do Writeln(integer(aux^))
En donde aux es una variable de tipo pointer, y si queremos eliminar los elementos de una lista también se puede hacer del siguiente modo:
for aux in ListaN do freemem(aux)
A continuación el código fuente 01, visto anteriormente con el uso de for in loop.
‒
Descargar
{$codepage utf8}
{$mode objfpc}
Uses sysutils,classes;
Var ListaN,ListaD:Tlist;
n:^integer;
d:^double;
i:byte;
aux:pointer;
Begin
randomize;
ListaN:=Tlist.create;
ListaD:=Tlist.create;
for i:=0 to 10 do
begin
new(n);new(d);
n^:=random(1000);
d^:=random;
ListaN.add(n);
ListaD.add(d);
end;
Writeln('ListaN');
Writeln('Capacidad = ',ListaN.Capacity);
Writeln('Cantidad = ',ListaN.Count);
i:=0;
for aux in ListaN do
Begin
Writeln('[',i:2,'] ',integer(aux^));
i+=1
End;
Writeln('Borrando');
for aux in ListaN do freemem(aux);
ListaN.clear;
ListaN.destroy;
Writeln('ListaD');
Writeln('Capacidad = ',ListaD.Capacity);
Writeln('Cantidad = ',ListaD.Count);
i:=0;
for aux in ListaD do
Begin
Writeln('[',i:2,'] ',double(aux^):0:3);
i+=1
End;
Writeln('Borrando');
for aux in ListaD do freemem(aux);
ListaD.clear;
ListaD.destroy
End.
Código fuente 7: Uso de for in loop.
Descargar
En caso se usan objetos en vez de punteros como se vio anteriormente podemos usar como variable de control un puntero o un objeto de la clase correspondiente que se usa en la lista. En caso de usar un puntero se debe hacer un solapamiento de la variable de control con la clase correspondiente al objeto. Es decir en el siguiente código:
for aux in lista do TPersona(aux).MostrarPersona;
La variable aux es de tipo pointer, entonces a esta variable se le debe hacer un solapamiento con la clase TPersona, del cual son los objetos que están en la lista.
Por otro lado en caso de usar un objeto como variable de control, entonces se debe hacer un solapamiento de la variable de control con el tipo de dato pointer. Es decir en el siguiente código:
for pointer(Persona) in lista do Persona.MostrarPersona;
Persona es un objeto de la clase TPersona y se hace un solapamiento con pointer para acceder a los elementos de la lista. En el siguiente ejemplo es el mismo ejemplo 04 pero con el uso de for in loop, usando como variable de control al objeto Persona.
‒
Descargar
{$codepage utf8}
{$mode objfpc}
Uses sysutils,classes;
Type
TPersona=class
Nombre,Ciudad:string;
Procedure MostrarPersona;
End;
Procedure TPersona.MostrarPersona;
Begin
Writeln('Nombre:',Nombre);
Writeln('Ciudad:',Ciudad)
End;
Var Lista:Tlist;
rpta:char;
Persona:TPersona;
Begin
Lista:=Tlist.create;
Repeat
Persona:=TPersona.create;
Write('Nombre : ');Readln(Persona.Nombre);
Write('Ciudad : ');Readln(Persona.Ciudad);
Lista.add(Persona);
Write('Desea continuar [S]i [N]o : ');readln(rpta)
Until (rpta='N') or (rpta='n');
for pointer(Persona) in lista do Persona.MostrarPersona;
Writeln('Capacidad = ',Lista.Capacity);
Writeln('Cantidad = ',Lista.Count);
Writeln('Borrando');
for pointer(Persona) in Lista do Persona.destroy;
Lista.clear;
Lista.destroy
End.
Código fuente 8: Uso de for in loop con objetos.
Descargar