请问如何根据已知字符快速定位文本文件的行?(100分)

  • 主题发起人 主题发起人 孤云
  • 开始时间 开始时间

孤云

Unregistered / Unconfirmed
GUEST, unregistred user!
文本文件的内容格式有四列组成
COL01,COL02,COL03,COL04
。。。
。。。
COLn1,COLn2,COLn3,COLn4
n在7000左右
我用
function findcol(COL1:String;COL2:String;filename:String):String;
var
A :TStringList;
B :TStringList;
begin
ID:='';
TRY
A:=TStringList.Create;
B:=TStringList.Create;
A.LoadFromFile(filename);
FOR i:=0 TO A.Count-1 DO
BEGIN
B.Delimiter:=',';
B.DelimitedText:=A.Strings;
IF ((COL1=B.Strings[2]) AND (COL2=B.Strings[3])) OR
((COL2=B.Strings[3]) AND (COL1=B.Strings[2])) THEN
BEGIN
ID:=B.Strings[0];
Break;
END;
END;
FINALLY
A.Free;
B.Free;
END;
Result:=ID;
end;
由于一次性要循环查找的东西实在太多
procedure output;
var
strfd :String;
col1 :String;
col2 :String;
filename :String;
begin
filename:='./data/data.txt';
n:=3000;
Repeat
strfd:=findcol(COL1:String;COL2:String;filename):
....
....

Untile n=-1 //这种重复查找过程要执行上百到上千次,程序执行起来这样的查找 方法速度特别慢,请问高手有什么比较好的查找和定位方法,谢谢

end;
 
把数据导到一个表里用SQL语句查询并处理。
 
赞同 。使用数据库查询的优势。
 
IF ((COL1=B.Strings[2]) AND (COL2=B.Strings[3])) OR
((COL2=B.Strings[3]) AND (COL1=B.Strings[2])) THEN
这个条件写错了吧?

利用HashTable,事先把文本文件的每行内容(COLn2,COLn3)生成一个Hash值,假设为Hn,以后就只要计算(COL1, COL2)或者(COL2, COL1)的Hash值是否能够在Hn中找得到就行了,这个速度是飞快的了,根本就不需要每次都这样循环:
FOR i:=0 TO A.Count-1 DO
BEGIN
....
END;
 
To 有畏
谢谢
是的,条件写错了,是
IF ((COL1=B.Strings[2]) AND (COL2=B.Strings[3])) OR
((COL1=B.Strings[3]) AND (COL2=B.Strings[2])) THEN
什么是HashTable,感觉跟C++中的map有点像,在Delphi中怎么实现,能否详细点,谢谢
 
根据VCL的TStringHash写的哈希表类。
unit zjHashedTable;

interface

uses
SysUtils,
Classes;

type
TzjStringHashProc = function(const aKey:string):Cardinal;
TzjHashItemDisposeProc = procedure(aData:Pointer);
TzjHashTableIterator = function(aKey:string;aData:Pointer;aParam:LongInt):Boolean;

PPzjHashItem = ^PzjHashItem;
PzjHashItem = ^TzjHashItem;
TzjHashItem = record
Next: PzjHashItem;
Key: string;
Data: Pointer;
end;

TzjHashedTable = class(TObject)
private
Buckets: array of PzjHashItem;
FHashProc: TzjStringHashProc;
FDisposeProc:TzjHashItemDisposeProc;
FOwnsItem:Boolean;
FCount:Integer;
function GetContents: TList;
function GetCapacity: Integer;
public
constructor Create(aHashProc:TzjStringHashProc = nil;aSize: Cardinal = 256);
destructor Destroy; override;
function Find(const aKey: string;aPos: Integer = -1): PzjHashItem;
function Insert(const aKey: string; aData: Pointer; FailIfExists:Boolean = False):Boolean;
procedure Clear;
function Remove(const aKey: string):Boolean;
function Extract(const aKey: string;out aData:Pointer):Boolean;
function Modify(const aKey: string; aData: Pointer): Boolean;
function GetItem(const aKey: string;out aData:Pointer): Boolean;
function Exists(const aKey:string):Boolean;
function Iterate(aIteratePrco:TzjHashTableIterator;aParam:LongInt):Boolean;
property Contents:TList read GetContents;
property DisposeProc:TzjHashItemDisposeProc read FDisposeProc write FDisposeProc;
property OwnsItem:Boolean read FOwnsItem write FOwnsItem;
property Count:Integer read FCount;
property Capacity:Integer read GetCapacity;
end;

implementation


function DefStringHash(const aKey:string):Cardinal;
var
I: Integer;
begin
Result := 0;
for I := 1 to Length(aKey) do
Result := ((Result shl 2) or (Result shr (SizeOf(Result) * 8 - 2))) xor
Ord(aKey);
end;

{ TzjHashedTable }

procedure TzjHashedTable.Clear;
var
I: Integer;
P, N: PzjHashItem;
begin
for I := 0 to Length(Buckets) - 1 do
begin
P := Buckets;
while P <> nil do
begin
N := P^.Next;
if Self.FOwnsItem then
Self.FDisposeProc(P.Data);
Dispose(P);
P := N;
end;
end;
FillChar(Buckets[0],Length(Buckets)*SizeOf(PzjHashItem),0);
FCount:=0;
end;

constructor TzjHashedTable.Create(aHashProc:TzjStringHashProc;aSize: Cardinal);
begin
if @aHashProc=nil then
Self.FHashProc:=@DefStringHash
else
Self.FHashProc:=@aHashProc;
SetLength(Buckets, aSize);
FillChar(Buckets[0],Length(Buckets)*SizeOf(PzjHashItem),0);
FCount:=0;
end;

destructor TzjHashedTable.Destroy;
begin
Clear;
inherited;
end;

function TzjHashedTable.Exists(const aKey: string): Boolean;
begin
Result:=Find(aKey)<>nil;
end;

function TzjHashedTable.Extract(const aKey: string;out aData: Pointer): Boolean;
var
Hash: Integer;
P,Prev:PzjHashItem;
begin
Result:=False;
Hash := FHashProc(aKey) mod Cardinal(Length(Buckets));
Prev:=nil;
P := Buckets[Hash];
while P <> nil do
begin
if P.Key = aKey then
begin
if Prev<>nil then
Prev.Next:=P.Next
else
Buckets[Hash]:=P.Next;
aData:=P.Data;
Dispose(P);
Dec(FCount);
Result:=True;
Break;
end
else
begin
Prev:=P;
P:=P.Next;
end;
end;
end;

function TzjHashedTable.Find(const aKey: string;aPos: Integer): PzjHashItem;
var
Hash: Integer;
begin
if aPos < 0 then
Hash := FHashProc(aKey) mod Cardinal(Length(Buckets))
else
Hash := aPos;
Result := Buckets[Hash];
while Result <> nil do
begin
if Result.Key = aKey then
Exit
else
Result := Result.Next;
end;
end;

function TzjHashedTable.GetCapacity: Integer;
begin
Result:=Length(Buckets);
end;

function TzjHashedTable.GetContents: TList;
var
I,J: Integer;
P: PzjHashItem;
begin
if FCount=0 then
begin
Result:=nil;
Exit;
end;
Result:=TList.Create;
Result.Count:=Self.FCount;
J:=0;
for I := 0 to Length(Buckets) - 1 do
begin
P := Buckets;
while P <> nil do
begin
Result.Items[J]:=P.Data;
Inc(J);
P:=P.Next;
end;
end;
end;

function TzjHashedTable.GetItem(const aKey: string;out aData: Pointer): Boolean;
var
P: PzjHashItem;
begin
P := Find(aKey);
if P=nil then
Result:=False
else
begin
aData:=P.Data;
Result:=True;
end;
end;

function TzjHashedTable.Insert(const aKey: string; aData: Pointer; FailIfExists:Boolean):Boolean;
var
Hash: Integer;
P,Bucket: PzjHashItem;
begin
Result:=False;
Hash := FHashProc(aKey) mod Cardinal(Length(Buckets));
P:=Self.Find(aKey,Hash);
if p=nil then
begin
New(Bucket);
Bucket.Key := aKey;
Bucket.Data := aData;
Bucket.Next := Buckets[Hash];
Buckets[Hash] := Bucket;
Inc(FCount);
Result:=True;
end
else if not FailIfExists then
begin
if Self.FOwnsItem then
Self.FDisposeProc(P.Data);
P.Data:=aData;
Inc(FCount);
Result:=True;
end;
end;

function TzjHashedTable.Iterate(aIteratePrco: TzjHashTableIterator;
aParam: Integer): Boolean;
var
I: Integer;
P: PzjHashItem;
begin
Result:=False;
for I := 0 to Length(Buckets) - 1 do
begin
P := Buckets;
while P <> nil do
begin
Result:=aIteratePrco(P.Key,P.Data,aParam);
if Result then Exit;
P:=P.Next;
end;
end;
end;

function TzjHashedTable.Modify(const aKey: string;aData: Pointer): Boolean;
var
P: PzjHashItem;
begin
P := Find(aKey);
if P = nil then
Result:=False
else
begin
if P.Data<>aData then
begin
if Self.FOwnsItem then
Self.FDisposeProc(P.Data);
P.Data:=aData;
Result:=True;
end
else
Result:=False;
end;
end;

function TzjHashedTable.Remove(const aKey: string): Boolean;
var
P:Pointer;
begin
Result:=Self.Extract(aKey,P);
if Result and Self.FOwnsItem then
Self.FDisposeProc(P);
end;

end.
 
还是导入到ms sql最好,本人以前做过一个就是吧文本文件通过程序整理后在导入到sql server中,十分麻烦,还是用sql语句最好
 
好的,谢谢各位
 
FindCol函数有很大优化,最起码将传filename参数,改为传入filename的内容,传一次问题看不出来,10,100,1000次的传入,每次load,free,不慢,我看才怪了。

BYW:记得findCol的字串参数加上const
 
To QQ在线
“FindCol函数有很大优化”
除了

function findcol(const COL1:String; const COL2:String;filename:TStringList):String;
外,还有哪些地方可以优化的,除了采用哈希表或SQL,不知道你还有什么好的方法
麻烦指点,谢谢
 
今天看到资料,突然发现Delphi也有哈希类,在IniFile中
THashedStringlist类
 
var
SL: TStringList;
i : Integer;
begin
SL := TStringList.Create;
SL.loadFromFile('FileName');
for i := 0 to SL.Count-1 do
begin
if Pos('String',SL)<>0 then
ShowMessage('所在行:' + IntToStr(i+1));
end;
end;
 
后退
顶部