ListView 重复第二个 TListItem.Caption 的项目

ListView repeating items from second TListItem.Caption

我有两个 StringList 分别加载(从文件)用户和用户 + 密码。我正在比较这些列表以确定(第一个列表的)哪个用户已经有密码(在第二个列表中),然后插入 ListView 谁有密码,谁还没有密码。

但是这里存在一个问题,从第二个 ListItem.Caption(用户)开始重复两次。

我该如何解决这个问题?

我加载到列表中的文件是:

users.dat

logins.dat

这是我最后一次尝试代码:

type
  TForm1 = class(TForm)
    Button1: TButton;
    ListView1: TListView;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
var
  L1, L2, LSplit: TStringList;
  L: TListItem;
  I, J: Integer;
begin
  L1 := TStringList.Create;
  L2 := TStringList.Create;
  LSplit := TStringList.Create;

  L1.LoadFromFile('users.dat');
  L2.LoadFromFile('logins.dat');

  for I := 0 to L1.Count - 1 do
  begin
    for J := 0 to L2.Count - 1 do
    begin
      LSplit.Clear;
      ExtractStrings(['|'], [], PChar(L2[J]), LSplit);
      if L1[I] = LSplit[0] then
      begin
        L := ListView1.Items.Add;
        L.Caption := LSplit[0];
        L.SubItems.Add(LSplit[1]);
        Break;
      end;
      L := ListView1.Items.Add;
      L.Caption := L1[I];
    end;
  end;
  L1.Free;
  L2.Free;
  LSplit.Free;
end;

end.
for I := 0 to L1.Count - 1 do
  begin
    found := false;
    L := ListView1.Items.Add;
    for J := 0 to L2.Count - 1 do
    begin
      LSplit.Clear;
      ExtractStrings(['|'], [], PChar(L2[J]), LSplit);
      if L1[I] = LSplit[0] then
      begin
        L.Caption := LSplit[0];
        L.SubItems.Add(LSplit[1]);
        found := true;
        Break;
      end;
    end;
    if not found then 
       L.Caption := L1[I];
  end;

另请注意,字典方法对于大型列表来说要快得多

你的内循环坏了。即使正在比较的 2 个 StringList 项目彼此不匹配,它也会向 ListView 添加项目。对于第一个列表中的每个用户,您将其添加到 ListView 的次数与第二个列表中条目的次数一样多。

您的代码应该看起来更像这样:

procedure TForm1.Button1Click(Sender: TObject);
var
  L1, L2, LSplit: TStringList;
  L: TListItem;
  I, J: Integer;
begin
  L1 := TStringList.Create;
  try
    L2 := TStringList.Create;
    try
      LSplit := TStringList.Create;
      try
        L1.LoadFromFile('users.dat');
        L2.LoadFromFile('logins.dat');

        for I := 0 to L1.Count - 1 do
        begin
          L := ListView1.Items.Add;
          L.Caption := L1[I];
          for J := 0 to L2.Count - 1 do
          begin
            LSplit.Clear;
            ExtractStrings(['|'], [], PChar(L2[J]), LSplit);
            if L1[I] = LSplit[0] then
            begin
              L.SubItems.Add(LSplit[1]);
              Break;
            end;
          end;
        end;
      finally
        LSplit.Free;
      end;
    finally
      L2.Free;
    end;
  finally
    L1.Free;
  end;
end;

也就是说,您不需要 3 个 TStringList 对象和 2 个循环。 2 TStringList 个对象和 1 个循环就足够了:

procedure TForm1.Button1Click(Sender: TObject);
var
  L1, L2: TStringList;
  L: TListItem;
  I: Integer;
begin
  L1 := TStringList.Create;
  try
    L2 := TStringList.Create;
    try
      L1.LoadFromFile('users.dat');
      L2.LoadFromFile('logins.dat');
      L2.NameValueSeparator := '|';

      for I := 0 to L1.Count - 1 do
      begin
        L := ListView1.Items.Add;
        L.Caption := L1[I];
        L.SubItems.Add(L2.Values[L1[I]]);
      end;
    finally
      L2.Free;
    end;
  finally
    L1.Free;
  end;
end;

您的代码的问题是您总是将第一个列表中的用户名添加到结果中,而不管您是否已经从第二个列表中添加了包含密码的用户名或没有。

为避免这种情况,您需要以一种方式编写代码,即只有在第二个列表中未添加用户名时,才会从第一个列表中添加用户名。

//If password exist in second list add username and password from second list
if L1[I] = LSplit[0] then
begin
  L := ListView1.Items.Add;
  L.Caption := LSplit[0];
  L.SubItems.Add(LSplit[1]);
  Break;
end
//Else add username from first list
else
begin
  L := ListView1.Items.Add;
  L.Caption := L1[I];
end;

另请注意,如果您的第二个列表包含第一个列表中不存在的用户名,您的应用程序将失败。

例如让我们检查下一个场景: users.dat

  • 用户 01
  • 用户 02
  • 用户 03

logins.dat

  • User01|test01
  • User02|test01
  • User04|test04

在上述情况下,您的最终结果将不包含来自 User04 的任何数据,因为它不存在于您的第一个列表中。

因此,我建议您使用不同的方法来迭代第二个列表,并为每个条目搜索第一个列表以查看用户名是否存在于其中。
如果确实如此,您可以编辑第一个列表中的条目以添加第二个列表中的密码信息。如果您在第一个列表中找不到用户名,则可以在其中添加用户名和密码。

这将向您保证最终结果将排除两个列表中的所有用户名,无论它们是在哪个列表中找到的。