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)

MyCombitationsこれには、実際に持っていて完全なリストと照合したいすべての組み合わせをリストした table が必要です。

スピードアップしたい場合は、組み合わせの永続的なテーブルと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

データを並べ替えることができる場合 ( Turbo powers SysToolsには、適切に機能する優れた並べ替えルーチンがあります)、2 つの入力リストと出力リストを使用してコードでこれをかなり迅速に行うことができます。この背後にある概念は単純です。

  1. 同じ方法でソートされた 2 つのリストを取得します。
  2. 左側が右側よりも小さい場合、右側にその値がないため、「欠落リスト」に追加し、左側のカーソルを増やします。
  3. それらが等しい場合は、両方をインクリメントします。
  4. 右側が左側よりも小さい場合は、右側のみをインクリメントします (オプションで「削除する必要がある」リストに追加します)。

このプロセスは「オールド マスター/ニュー マスター」プロセスと呼ばれることもあり、両方のリストを 1 回だけ参照するだけなので非常に高速です。

簡単な例:

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;

次のコードは、テストに使用したものです。これは単なる例ですが、実際の状況では、キーが適切にソートされ、数字が正しくパディングされ、必要に応じて大文字と小文字が区別されるようにキーを作成します。ターボ パワー ソート ルーチンを使用する場合、2 つのリストの代わりに 2 つのソートを使用できますが、最終的な結果は同じです。

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 に答える
1

75.000は多くありません。文字のリストと数字のリストを 2 つの別個の TStringList にロードします。適切な次元で動的配列を作成します (インデックスは、これら 2 つの文字列リストへのインデックスになります)。いっぱいにしてください。データをロードし、配列の各行をマークします。マークされていないすべての要素を出力します。

疑似コード (未テスト):

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 に答える