为什么此搜索无法生成正确的结果?

时间:2011-01-16 14:16:53

标签: delphi

下面是找到同一个客户,如果他在列表中,则该号码加一个。如果他不在列表中,只需将他添加到列表中。

我使用搜索功能执行此操作,但失败并生成了错误的记录。它无法找到客户或合适数量的客户。 但是,如果我使用For..loop迭代列表,它会很好并且可以找到客户并在for..loop搜索过程中添加新客户。 (我没有在这里粘贴.loop搜索程序)。

另一个问题是设置list.sorted true和false之间没有区别。似乎搜索功能不正确。这个搜索功能来自delphi教科书的一个例子。

以下是Delphi 7。

谢谢。

Procedure Form1.create;
begin
list:=Tstringlist.create;
list.sorted:=true;  // Search function will generate exactly Same and Incorrect 
                    //records no matter list.sorted is set true or false. 
//list.duplicates:=dupignore;

end;

Procedure addcustomer;
var
customer: string;
    begin
    //... Here is the code part that P1 is created as regular expression (omitted)
    while p1.MatchAgain do begin //p1 is regular expression
    customer:=p1.MatchedExpression; // try to match customer name.
    if (search(customer)=false) then begin //this line output wrong number
   // if (forloopsearch(customer)=false) then begin // this forloopsearch is ok
    list.Add(customer+'=1');
    end;
    allcustomer:=allcustomer+1; // global allcustomer is integer to count all customers

    end;


Function Tform1.search(customer: string): boolean;
var
 fre:string;
 num:integer;
 L:integer;
 R:integer;
 M: Integer;
 CompareResult: Integer;
 found: boolean;
begin
result:=false;
found:=false;
L := 0;
R := List.Count - 1;
while (L <= R) and ( not found ) do
begin
    M := (L + R) div 2;
    CompareResult := Comparetext(list.Names[m]), customer);
    if (compareresult=0) then
    begin
      fre:=list.ValueFromIndex [m];
      num:=strtoint(fre);
      num:=num+1;
      list.ValueFromIndex[m]:=inttostr(num);
      Found  := True;
      Result := true;
      exit;
      end
    else if compareresult > 0 then
      r := m - 1
    else
      l := m + 1;
  end;

end;

编辑:

谢谢大家。

为了澄清这个问题,我在这里从我的电脑上复制了测试代码,对不起,我很抱歉。

以下是包含3个人姓名的名称文件(总共45个johns,45个maries和45个erics)。

mary, mary, mary, john, john, john, eric, eric, eric,
mary, mary, mary, john, john, john, eric, eric, eric,
mary, mary, mary, john, john, john, eric, eric, eric,
mary, mary, mary, john, john, john, eric, eric, eric,
mary, mary, mary, john, john, john, eric, eric, eric,
mary, mary, mary, john, john, john, eric, eric, eric,
mary, mary, mary, john, john, john, eric, eric, eric,
mary, mary, mary, john, john, john, eric, eric, eric,
mary, mary, mary, john, john, john, eric, eric, eric,
mary, mary, mary, john, john, john, eric, eric, eric,
mary, mary, mary, john, john, john, eric, eric, eric,
mary, mary, mary, john, john, john, eric, eric, eric,
mary, mary, mary, john, john, john, eric, eric, eric,
mary, mary, mary, john, john, john, eric, eric, eric,
mary, mary, mary, john, john, john, eric, eric, eric,

forloopsearch将生成以下内容。下面是一个复制结果,它读取键和值并添加到列表视图中(使用listview的项目的add方法)。这个结果是正确的,也是我想要的。

  mary  45
  john  45
  eric  45

以下是forloopsearch。

Function Tform1.forloopsearch(customer: string): boolean;
var
 fre:string;
 i: integer;
aname:string;
 num:integer;
begin
result:=false;
for i:=0 to list.count-1 do begin
  aname:=list.names[i];
  if aname=customer then
      begin
      fre:=list.ValueFromIndex [i];
      num:=strtoint(fre);
      num:=num+1;
      list.ValueFromIndex[i]:=inttostr(num);
      Result := true;
      End;
 end;
end;

上面的forloopsearch函数输出是正确的,它会在迭代中修改键的值。

搜索功能将输出以下内容。这不正确,不是我想要的。它还修改了循环中键的值,但输出显然是错误的。

在这两种情况下,如上所示,在创建表单时,list.sorted设置为true。它们都使用相同的过程来迭代列表并将键和值按顺序复制到列表视图中(通过使用add方法)。以下是搜索功能结果。

mary    3   
john    2   
john    1   
eric    1   
eric    4   
eric    40
mary    3   
john    1   
john    40
john    1   
mary    39

如何解决它。再次感谢你。

2 个答案:

答案 0 :(得分:1)

(最初的问题是StringList上的二进制搜索失败,原因是搜索执行时列表没有排序。请参阅有关问题的评论。)

<小时/> 我要做的是保持stringlist始终排序,而不是'Name = Value'对来保持出现的频率,使用Objects属性。这将有助于避免代码最初具有的Integer&lt; - &gt; String转换,并且可以通过以下方式实现:list.Objects[i] := Pointer(f + 1);

使用stringlist的Find方法查明条目是否已存在。 Find本身执行二进制搜索,您不需要第三方代码来执行此操作。如果该项目已存在,只需增加频率即可。如果该项不存在,则该函数设置的Index参数是应插入项的位置(请参阅上面的文档链接)。调用受保护的方法InsertItem以插入新项目。 protected 调用的原因是为了避免不必要地再次运行find方法(请参阅'classes.pas'中的TStringList.AddObject函数)。这将通过某事实现。像:

type
  TSL = class(TStringList);

var
  i: Integer;
  s: string;
begin
  s := 'Joe';
  if list.Find(s, i) then
    list.Objects[i] := Pointer(Integer(list.Objects[i]) + 1)
  else
    TSL(list).InsertItem(i, s, Pointer(1));
end;


但是你真的需要描述和测试替代品,否则它都是基于猜测。

编辑:我想注意,如果此过程之外没有添加/删除项目,则可以保留字符串列表的已排序属性,然后 protected hack是不必要的,因为那时可以使用InsertObject方法。

答案 1 :(得分:0)

也许这就是你所需要的

var
    sl1, sl2: TStringList;
    sPrev: string;
    I: Integer;
begin
    sl1 := TStringList.Create;
    sl2 := TStringList.Create;
    try
        sl1.CommaText := 'mary, mary, eric, eric, john, mary, john, john,  eric, eric';
        sl1.Sorted := True;

        sPrev := '';
        for I := 0 to sl1.Count - 1 do
        begin
            if sl1[I] <> sPrev then
                sl2.Add(sl1[I]+'=1')
            else
                sl2.ValueFromIndex[sl2.Count-1] := IntToStr(StrToInt(sl2.ValueFromIndex[sl2.Count-1])+1);
            sPrev := sl1[I];
        end;

        for I := 0 to sl2.Count - 1 do
            ListView1.AddItem(sl2[I], nil);

    finally
        sl1.Free;
        sl2.Free;
    end;
end;