3

我有 3 个列表,我将在这里简化它们。

字母
A
B
C 列表

数字列表
1
2
3

混合
A,1
A,2
B,2
B,3
C,1
C,3

我需要知道缺少什么:
A,3
B,1
C,2

字母列表有大约 85 个条目
,数字列表有大约 500 个条目。

混合列表有大约 75,000 个条目。

我可以使用数据库查询(mysql 5.0)或 Turbo Delphi 2006 来处理文本文件。找到丢失的东西的最佳方法是什么?

谢谢,
戴夫

4

5 回答 5

3

假设您在 SQL 表中都有两个列表,则交叉连接将产生所有组合:

SELECT
  Letter + ',' + Number AS Combination
FROM
  NumberList,
  LetterList

使用组合结果(可能将其保存到临时表中),您可以使用 NOT EXISTS 查询来查找缺少的内容:

SELECT
  Combination
FROM
  AllCombinations AS a
WHERE
  NOT EXISTS 
  (SELECT 1 FROM MyCombitations AS m WHERE m.Combination = a.Combination)

这将需要一个 table MyCombitations,其中列出了您实际拥有的所有组合并希望对照完整列表进行检查。

如果你想加快速度,你应该使用永久的组合表和MyCombitations.Combination字段索引。对于重复查询,这绝对是可取的。

于 2008-11-06T09:44:16.877 回答
2

无需创建额外的表。以下查询也可以正常工作:

SELECT c.chr, n.num
FROM chars c, nums n
 WHERE NOT EXISTS (SELECT 1
                     FROM mix m
                    WHERE m.chr = c.chr AND m.num = n.num)
于 2008-11-06T18:21:06.287 回答
1

75.000 并不多。将字母列表和数字列表加载到两个单独的 TStringList 中。创建具有适当维度的动态数组(索引将是这两个字符串列表的索引)。填补;填写(表格,资料。加载数据并标记数组中的每一行。输出所有未标记的元素。

在伪代码(未经测试)中:

var
  i1, i2: integer;
  sl1, sl2: TStringList;
  cross: array of array of boolean;
begin
  // load data into sl1, sl2
  SetLength(cross, sl1.Count, sl2.Count);
  for i1 := 0 to sl1.Count - 1 do
    for i2 := 0 to sl2.Count - 1 do
      cross[i1, i2] := false;
  // for each element in 'combined' list
    // split it into elements s1, s2
    i1 := sl1.IndexOf(s1);
    i2 := sl2.IndexOf(s2);
    if (i1 < 0) or (i2 < 0) then
      // report error
    else
      cross[i1, i2] := true;
  for i1 := 0 to sl1.Count - 1 do
    for i2 := 0 to sl2.Count - 1 do
      if not cross[i1, i2] then
        // output sl1[i1], sl2[i2]
end;
于 2008-11-06T09:53:43.910 回答
1
SELECT letter,number FROM lettersTable l , numbersTable n WHERE
(
    SELECT count(*) 
    FROM 
        (
            SELECT * 
            FROM combinationsTable 
            WHERE l.letter=combinationsTable.letter AND n.number = combinationsTable .number
        ) AS temp
) = 0;

这依赖于 SELECT * FROM A,B 测试所有组合(隐式交叉连接)。

于 2008-11-06T10:10:35.373 回答
1

如果您可以对数据进行排序(Turbo powers SysTools有一个运行良好的排序例程),那么您可以使用两个输入列表和一个输出列表在代码中相当快地完成此操作。这背后的概念很简单:

  1. 取两个列表,以相同的方式排序
  2. 如果左侧小于右侧,则右侧缺少该值,因此将其添加到“缺失列表”并增加左侧的光标。
  3. 如果它们相等,则增加两者,
  4. 如果右侧小于左侧,则仅增加右侧(可选添加到“必须删除”列表)。

这个过程有时被称为“老主人/新主人”过程,而且速度非常快,因为您只需走一遍这两个列表。

简单的例子:

var
  ListL : tStringList; // the left list
  ListR : tSTringList; // the right list
  ListA : tSTringList; // the Add List (should start empty)
  ListD : tStringList; // the Delete list (should start empty)
  iCurL : integer;     // Left Cursor
  iCurR : integer;     // Right Cursor
  iRes  : integer;     // result of compare
begin
  iCurL := 0;
  iCurR := 0;
  ListL := tStringList.create;
  ListR := tSTringList.create;
  ListA := tSTringList.create;
  ListD := tStringList.create;
  InitAndLoadLists(ListL,ListR,ListA,ListD);
  while (iCurL <= ListL.Count-1) and (iCurR <= ListR.Count-1) do
    begin
      iRes := CompareStr(ListL.Strings[iCurL],ListR.Strings[iCurR]);
      if iRes = 0 then
        begin
          inc(iCurL);
          inc(iCurR);
        end;
      if iRes < 0 then
        begin
          ListA.Add(ListL.Strings[iCurL]);
          inc(iCurL);
        end;
      if iRes > 0 then
        begin
          listD.Add(ListR.Strings[iCurR]);
          inc(iCurR);
        end;
    end;
  while (iCurL <= ListL.Count-1) do
    begin
      listA.Add(ListL.Strings[iCurL]);
      inc(iCurL);
    end;
  while (iCurR <= ListR.Count-1) do
    begin
      listD.Add(ListR.Strings[iCurR]);
      inc(iCurR);
    end;
  ShowMessage( 'ADDS' + ^M+^J + ListA.Text);
  ShowMessage( 'DELS' + ^M+^J + ListD.Text);
end;

以下代码是我用于测试的代码。这只是一个例子,但在现实世界的情况下,我会构建我的密钥,以便它们能够正确排序、正确的填充数字,并在适当的情况下强制大小写。如果您使用 turbo power 排序例程,您可以使用两个排序而不是两个列表,但最终效果是相同的。

procedure InitAndLoadLists(ListL, ListR, ListA, ListD: TStringList);
begin
  ListL.Add('A,1');
  ListL.Add('B,3');
  ListL.Add('C,2');
  ListR.Add('A,2');
  ListR.Add('B,3');
  ListR.Add('C,4');
end;

编辑:代码在 Delphi 2009 中测试并且表现正常。

于 2008-11-06T15:56:53.597 回答