【问题标题】:Search multiple list for missing entries在多个列表中搜索缺失的条目
【发布时间】:2010-09-21 01:13:31
【问题描述】:

我有 3 个列表,我将在此处将它们简单化。

字母列表
一个

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 来处理文本文件。找到缺失内容的最佳方法是什么?

谢谢,
戴夫

【问题讨论】:

    标签: sql delphi comparison list


    【解决方案1】:

    假设您的两个列表都在 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)
    

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

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

    【讨论】:

      【解决方案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)
      

      【讨论】:

      • 这与 LIMIT 100 正是我想要的。谢谢大家!
      【解决方案3】:

      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;
      

      【讨论】:

        【解决方案4】:
        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 测试所有组合(隐式交叉连接)。

        【讨论】:

          【解决方案5】:

          如果您可以对数据进行排序(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 sort 例程,您可以使用两个排序而不是两个列表,但最终效果是相同的。

          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 中测试并且表现正常。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2012-04-16
            • 1970-01-01
            • 1970-01-01
            • 2017-07-12
            相关资源
            最近更新 更多