PDA

Ver la Versión Completa : Leer y ordenar fichero en delphi


izubal
16-10-2008, 08:19:13
Hola,

Llevo un par de semanas programando en Delphi y necesito ayuda.
Tengo que leer un fichero plano. Tengo que ordenar todas las líneas en base a dos campos y cada línea contiene varios campos que están separados por el simbolo |.
Se leer las líneas y también encontrar este símbolo con la función pos, pero no tengo ni idea de como ordenarlos.

¿Alguien me podrí dar una pista?

Gracias, Un saludo

Lepe
16-10-2008, 08:44:02
campo1 | campo2 | campo3 | campo4


¿por qué campos tienes que ordenar?
¿campo1 y campo 2?
o ¿puedes necesitar ordenar por campo2 y campo3 sin tener en cuenta el campo1?.
- ¿el usuario debe poder elegir los campos de ordenación?

Cada ordenación necesitará de algo distinto.

Saludos

izubal
16-10-2008, 08:47:48
Hola,

en total cada línea cuenta de 12 campos
campo1 | campo2 | campo3 | campo4 | ...
y tengo que ordenar las líneas en base al campo2 y campo8
El usuario no tiene que seleccionar por qué campo ordenar, sino que tiene que ser en ascendente.

gracias

Neftali [Germán.Estévez]
16-10-2008, 08:53:31
La forma más sencilla que se me ocurre es utilizar un TStringList que ya posee métodos de ordenación.

Monta una Clave (string) utilizando los dos campos que necesitas para ordenar, manteniendo en todos los casos la misma longitud y conviertiendolos a String si no lo son. Luego esa clave se la pasas a un StringList y le mandas que ordene. Ya tendrás las claves ordenadas.

A ver si me explico; Suponiendo que los campos fueran Nombre y Cantidad, por poner uno de cada tipo:

Carlos--234--...
Felipe--123--...
Ana-23--...
Juan--3456--...
Andres--4--...

Se trataría de montar la cadena de esta forma:
(Nombre rellenando hasta 15 y Cantidad también); En este caso he rellenado con 0, pero puedes usar otro caracter.

000000000Carlos000000000000234
000000000Felipe000000000000123
000000000000Ana000000000000023
00000000000Juan000000000003456
000000000Andres000000000000004

De esta forma ahora ya puedes pasar estas cadenas y te ordenará correctamente. El pointer (TObject) puedes utilizarlo para apuntar a la posición de la lista inicial.

No se si me expliqué más o menos claramente.

izubal
16-10-2008, 08:58:56
Si, creo que ya te he entendido.

1. Montó la cadena.
2. Pasarlas al StringList
3. Usar el método de ordenación que tiene el StringList

pero y al StringList le tendría que decir por qué campo ordenar no? hay ya no lo tengo... vamos que no he entendido muy bien.
Si me puedes aclarar este último punto....

gracias
un saludo

izubal
16-10-2008, 09:08:16
Voy a intentarlo.
estoy mirando como funciona el objeto StringList y si no lo consigo ya vuelvo a escribir.

Gracias por todo.
Un saludo

izubal
16-10-2008, 09:55:47
Hola,

Tengo una duda.
Cargo en el TStringList todas las líneas del fichero.
pero el método sort no tiene como pasarle los parámetros.

sl := TStringList.Create;
try
Reset(ftIN);
Rewrite(ftOUT);
while (not EOF(ftIN)) and (Error<> 1) do
begin
Readln(ftIN, S);
sl.Add(S);
...

pero como le digo que quiero ordenarlo en base al campo2 y 8??
con el método xprocs.strTokenToStrings(S,'|',s2); puedo cargar en otro TStringList (s2) todos los campos que tiene pero no se como seguir.

un saludo.

Neftali [Germán.Estévez]
16-10-2008, 11:18:34
Por pasos:
(1) Carga el fichero en un TStringList (llamaremos el original). Hay un método que lo hace, esa es otra de las ventajas del TStrigList.


TS.loadFromFile('nombrefichero')


(2) Monta un segundo TStringList con las cadenas; Ese segundo es el que utilizaremos para ordenar. Tendrás las cadenas y el apuntador e la posición en la lista original.


var
i:Integer;
pi:PInteger;
begin
...
TS2 := TStringList.Create();
...
for i := 0 to (TS.Count - 1) do begin
Str := 'Cadena con los campos 2 y 8' // CURRO PARA TÍ
// tendrás en Str concatenados el campo2 y el campo8

// Añadirlo a la segunda lista
pi := Pointer(i);
// Añadimos a la segunda lista el String y la posicion en la original (usamos el puntero para colocar la posicion)
TS2.AddObject(Str, TObject(pi));
end;

// Cuando salgas del FOR, en TS2 tendrás tantas cadenas como en TS
// pero sólo con los campos2 y 8


Ahora tu segunda lista tiene las cadenas 2 y 8 y la posicion en la lista original; Al ordenar, ordenará por las cadenas y segirás teniendo cada cadena con un entero que te dirá la posición en la lista original.

(3) Ordenar.


TS2.Sort();


Si originalmente la lista estaba así (TS):
Lunes
Martes
Miercoles
Jueves
Viernes
Sábado
Domingo

La segunda lista estará así (TS2) despues de ordenar; Lo segundo es el apuntador:
Domingo (7)
Jueves(4)
Lunes(1)
Martes(2)
Miercoles(3)
Sábado(6)
Viernes(5)

Por lo tanto puedes reordenar la lista original en una tervera (TS3) utilizando algo así:


for i := 0 to (TS2.Count - 1) do begin
// cadena en la segunda lista
Str := TS2[i];
// posicion en la lista original
j := Integer(TS2.Objects[i]);
// añadirlo a la ternera lista
TS3.Add(TS.[j]);
end;


Espero que quede más claro.

Lepe
16-10-2008, 11:25:59
Edito: Neftali sigue siendo el más rápido del Oeste.... :D.

(No sé si borrar el mensaje o dejarlo, lo dejo de momento, si te lías más, olvídame :D :D, prácticamente digo lo mismo que Neftali)

Vamos por partes:
- Para cargar el fichero, puedes usar un stringlist llamado fichero y usar fichero.LoadFromfile('ruta completa.txt');

Ahora por cada elemento de ese string, tienes que recorrerlo y ponerlo en formato:
000000000Carlos000000000000234

Suponiendo que "Carlos" es el campo1 y "234" es el campo8

Estos strings con formato especial, vamos a cargarlo en otro stringlist llamado Aordenar, de forma que lo añadimos así:

fichero := TStringlist.create;
Aordenar := TStringlist.create;
for i:= 0 to fichero.count-1 do
begin
strConCeros := pues eso, la cadena con los ceros, usa el xprocs o lo que sea para armar la cadena
aordenar.AddObject(strConCeros, pointer(i));
end;
aordenar.sort;


Un ejemplito, Supongamos que aordenar (después de llamar a Sort) tiene esto

string Object[i]
00000Antonio 3
00000Carlos 1


Eso significa que fichero[3] tendrá a "Antonio" y es el primer nombre en orden alfabético que existe en el fichero.

También significa que en segundo lugar de la lista ordenada, está "Carlos" el cual se encuentra en fichero[1]

Quizás sea un lío, te aconsejo probar con algo así

var str:string;
begin
for i:= 0 to Aordenar.count-1 do
begin
str := Aordenar[i] + ' está en el índice '+ IntTostr(integer(Aordenar.objects[i])) + ' de fichero';
ShowMessage(str);
end;


Dicho de otra forma Aordenar.objects[i] guarda la linea en que se encuentra ese individuo en el archivo.

Saludos

izubal
16-10-2008, 11:28:18
OK.
Con las explicaciones que me habeís dado espero conseguirlo esta tarde.
Ya os comentaré que tal me ha ido.

muchas gracias a los dos.
un saludo

Neftali [Germán.Estévez]
16-10-2008, 11:45:11
...prácticamente digo lo mismo que Neftali

Bueno, eso debe ser que no vamos tan mal encaminados, pistolero! :):)

izubal
16-10-2008, 15:59:25
Hola,

lo he conseguido!!
ahora lo veo sencillo, pero no me salía!!!

Muchas muchas gracias.

un saludo

izubal
16-10-2008, 16:57:14
Hola,

lo he conseguido!!
ahora lo veo sencillo, pero no me salía!!!

Muchas muchas gracias.

un saludo