2012-01-14 63 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