2012-01-14 97 views
3

我有這個問題:從一個空列表(0元素)開始,我想檢查一個元素是否存在或不存在於此列表中。如果這個記錄不在列表中,那麼我將這個記錄添加到列表中,否則更新列表中的元素。 我曾嘗試編寫這些代碼:列表和包含方法

program Project1; 

{$APPTYPE CONSOLE} 

{$R *.res} 

uses 
    System.SysUtils, System.Generics.Collections, System.Generics.Defaults; 

type 
    TDBStats = record 
    Comb: Integer; 
    Freq: Integer; 
    end; 
    TDBStatsList = TList<TDBStats>; 

procedure Add(ODBStats: TDBStatsList; const Item: TDBStats); 
var 
    rItem: TDBStats; 
begin 
    rItem := Item; 
    rItem.Freq := 1; 
    oDBStats.Add(rItem); 
end; 

procedure Update(ODBStats: TDBStatsList; const Item: TDBStats; const Index: Integer); 
var 
    rItem: TDBStats; 
begin 
    rItem := Item; 
    Inc(rItem.Freq); 
    oDBStats[Index] := rItem; 
end; 


var 
    oDBStats: TDBStatsList; 
    rDBStats: TDBStats; 
    myArr: array [0..4] of integer; 
    iIndex1: Integer; 
begin 
    try 
    myArr[0] := 10; 
    myArr[1] := 20; 
    myArr[2] := 30; 
    myArr[3] := 40; 
    myArr[4] := 10; 

    oDBStats := TList<TDBStats>.Create; 
    try 
     for iIndex1 := 0 to 4 do 
     begin 
     rDBStats.Comb := myArr[iIndex1]; 
     if oDBStats.Contains(rDBStats) then 
      Update(oDBStats, rDBStats, oDBStats.IndexOf(rDBStats)) 
     else 
      Add(oDBStats, rDBStats); 
     end; 
     // Check List 
     for iIndex1 := 0 to Pred(oDBStats.Count) do 
     Writeln(oDBStats[iIndex1].Comb:3, oDBStats[iIndex1].Freq:10); 
    finally 
     oDBStats.Free; 
    end; 

    except 
    on E: Exception do 
     Writeln(E.ClassName, ': ', E.Message); 
    end; 
    Readln; 
end. 

,應該返回這樣的結果:

10  2 
20  1 
30  1 
40  1 
50  1 

但返回這個結果:

10  1 
20  1 
30  1 
40  1 
50  1 
10  1 

我已經明白有關的問題:當我使用oDBStats .Contains(rDBStats)它控制rDBStats元素是否包含在列表中;第一次沒有找到它並添加到列表中;但是當它添加到列表中時,我將freq字段更新爲1;所以第二次當我再次檢查正在與freq = 0 rdbstats沒有發現它。 正如我可以解決這個問題?我需要一個計數器,我從輸入中得到一個「梳子」,我想檢查這個「梳子」是否出現在列表中,從記錄的另一個字段的值中顯示出來。如果我在列表中找到「梳子」,那麼我會更新freq字段。 感謝您的幫助。

+0

由於隨機選擇的類型名稱,您的代碼很難閱讀;使用'TDBStatList'而不是'TDBStats','TDBStat'而不是'PDBStats'。 – kludg 2012-01-14 14:39:01

+0

完成,所以我希望它可以幫助更好。 – 2012-01-14 14:46:46

+0

'Freq'字段值也在'Contains'方法中測試;簡單地在'rDBStats.Comb:= myArr [iIndex1];'之後添加'rDBStats.Freq:= 1;'行;給出正確的結果,但這不是一般的解決方案;你需要一個不同的比較器作爲你的列表。 – kludg 2012-01-14 15:05:34

回答

6

當您在通用列表上調用Contains時,它會查看給定值是否已經在列表中。您的情況下的值是一個由兩個字段組成的記錄。由於您沒有指定自定義比較器,Delphi將使用默認比較器,在記錄的情況下進行二進制比較。所以只有當兩個記錄是二進制相等時,它們纔會被視爲相等。

爲了使您的示例工作,您必須指定一個自定義比較器,該比較器僅比較記錄的梳狀字段。這是一個例子:

oDBStats := TList<TDBStats>.Create(TDelegatedComparer<TDBStats>.Create(
function(const Left, Right: TDBStats): Integer 
begin 
    result := CompareValue(Left.comb, Right.comb); 
end)); 

此外,您的更新例程中有一個錯誤。不是遞增現有值,而是遞增項目參數的未定義值。第一行的變化應該使其工作:

rItem := oDBStats[Index]; 
    Inc(rItem.Freq); 
    oDBStats[Index] := rItem; 
1

你有錯誤的數據結構,因爲你真正需要的是dictionary

使用列表最根本的問題是要在保存記錄的子集搜索。但是列表不是爲此設置的。通過使用TDictionary<Integer, Integer>重寫來解決問題。

我可以推薦你仔細閱讀dictionary code example at the Embarcadero docwiki

字典的關鍵是你所說的comb和價值是freq。要添加一個項目你這樣做:

if Dict.TryGetValue(Comb, Freq) then 
    Dict[Comb] := Freq+1 
else 
    Dict.Add(Comb, 1); 

我假設你的字典聲明如下:

var 
    Dict: TDictionary<Integer, Integer>; 

,創造這樣的:

Dict := TDictionary<Integer, Integer>; 

您可以枚舉字典用簡單的for in循環。

var 
    Item: TPair<Integer, Integer>; 
... 
    for Item in Dict do 
    Writeln(Item.Key:3, Item.Value:10); 

雖然被警告字典會以奇數順序列舉。打印前您可能希望排序。

如果您希望在字典中存儲與每個條目相關的更多信息,請將其他字段放入記錄中。

type 
    TDictValue = record 
    Freq: Integer; 
    Field1: string; 
    Field2: TDateTime; 
    //etc. 
    end; 

然後你的字典變成TDictionary<Integer, TDictValue>

+0

感謝您的建議,我看了這裏:http://docwiki.embarcadero.com/CodeSamples/en/Generics_Collections_TDictionary_(Delphi)和我已經理解的例子;但我有一個小問題要理解,因爲我可以在我的情況下做。特別是在我聲明的類型節中?例如我有:TDBStatsList = TList 並應該寫:TDBStatsList = TDictionary ;但它會讓我在Comb中出錯。如果我理解得好,這個「梳子」代表主鍵。可以嘗試舉一個例子,我可以更好地理解;因爲我第一次使用tdictionary。再次感謝。 – 2012-01-14 14:59:47

+0

謝謝,我剛剛讀過你的例子。我嘗試它。再次非常感謝 – 2012-01-14 15:01:39

+0

我簡化了記錄TDBStats只使用兩個字段:comb(作爲主鍵)和freq作爲通用字段;在實際應用中,這個記錄是由很多字段組成的,這些字段在得到一個元素梳的時候都會被更新。看你的例子我應該添加所有這些領域:Dict.TryGetValue(梳子,頻率)有Dict.TryGetValue(梳子,頻率,Field1,field2,fieldn)?以我發佈的示例代碼爲例,我只能更新部分,我檢查元素是否存在或不使用Tdictionary? – 2012-01-14 15:16:06